OSDN Git Service

Fix to setting the normal texture if vertex coloring is enabled.
authorKaelthas_Spellsinger@o2.pl <Kaelthas_Spellsinger@o2.pl@75d07b2b-3a1a-0410-a2c5-0572b91ccdca>
Mon, 13 Jun 2011 17:47:24 +0000 (17:47 +0000)
committerKaelthas_Spellsinger@o2.pl <Kaelthas_Spellsinger@o2.pl@75d07b2b-3a1a-0410-a2c5-0572b91ccdca>
Mon, 13 Jun 2011 17:47:24 +0000 (17:47 +0000)
git-svn-id: http://jmonkeyengine.googlecode.com/svn/trunk@7612 75d07b2b-3a1a-0410-a2c5-0572b91ccdca

engine/src/blender/com/jme3/scene/plugins/blender/helpers/v249/MaterialHelper.java
engine/src/blender/com/jme3/scene/plugins/blender/helpers/v249/MeshHelper.java
engine/src/blender/com/jme3/scene/plugins/blender/helpers/v249/TextureHelper.java

index 6b8c2c8..8841744 100644 (file)
@@ -62,649 +62,639 @@ import com.jme3.texture.Texture.WrapMode;
 import com.jme3.util.BufferUtils;\r
 \r
 public class MaterialHelper extends AbstractBlenderHelper {\r
-\r
-    private static final Logger LOGGER = Logger.getLogger(MaterialHelper.class.getName());\r
-    protected static final float DEFAULT_SHININESS = 20.0f;\r
-    public static final String TEXTURE_TYPE_COLOR = "ColorMap";\r
-    public static final String TEXTURE_TYPE_DIFFUSE = "DiffuseMap";\r
-    public static final String TEXTURE_TYPE_NORMAL = "NormalMap";\r
-    public static final String TEXTURE_TYPE_SPECULAR = "SpecularMap";\r
-    public static final String TEXTURE_TYPE_GLOW = "GlowMap";\r
-    public static final String TEXTURE_TYPE_ALPHA = "AlphaMap";\r
-    public static final Integer ALPHA_MASK_NONE = Integer.valueOf(0);\r
-    public static final Integer ALPHA_MASK_CIRCLE = Integer.valueOf(1);\r
-    public static final Integer ALPHA_MASK_CONE = Integer.valueOf(2);\r
-    public static final Integer ALPHA_MASK_HYPERBOLE = Integer.valueOf(3);\r
-    protected final Map<Integer, AlphaMask> alphaMasks = new HashMap<Integer, AlphaMask>();\r
-\r
-    /**\r
-     * The type of the material's diffuse shader.\r
-     */\r
-    public static enum DiffuseShader {\r
-\r
-        LAMBERT, ORENNAYAR, TOON, MINNAERT, FRESNEL\r
-    }\r
-\r
-    /**\r
-     * The type of the material's specular shader.\r
-     */\r
-    public static enum SpecularShader {\r
-\r
-        COOKTORRENCE, PHONG, BLINN, TOON, WARDISO\r
-    }\r
-    /** Face cull mode. Should be excplicitly set before this helper is used. */\r
-    protected FaceCullMode faceCullMode;\r
-\r
-    /**\r
-     * This constructor parses the given blender version and stores the result. Some functionalities may differ in different blender\r
-     * versions.\r
-     * \r
-     * @param blenderVersion\r
-     *        the version read from the blend file\r
-     */\r
-    public MaterialHelper(String blenderVersion) {\r
-        super(blenderVersion);\r
-        // setting alpha masks\r
-        alphaMasks.put(ALPHA_MASK_NONE, new AlphaMask() {\r
-\r
-            @Override\r
-            public void setImageSize(int width, int height) {\r
-            }\r
-\r
-            @Override\r
-            public byte getAlpha(float x, float y) {\r
-                return (byte) 255;\r
-            }\r
-        });\r
-        alphaMasks.put(ALPHA_MASK_CIRCLE, new AlphaMask() {\r
-\r
-            private float r;\r
-            private float[] center;\r
-\r
-            @Override\r
-            public void setImageSize(int width, int height) {\r
-                r = Math.min(width, height) * 0.5f;\r
-                center = new float[]{width * 0.5f, height * 0.5f};\r
-            }\r
-\r
-            @Override\r
-            public byte getAlpha(float x, float y) {\r
-                float d = FastMath.abs(FastMath.sqrt((x - center[0]) * (x - center[0]) + (y - center[1]) * (y - center[1])));\r
-                return (byte) (d >= r ? 0 : 255);\r
-            }\r
-        });\r
-        alphaMasks.put(ALPHA_MASK_CONE, new AlphaMask() {\r
-\r
-            private float r;\r
-            private float[] center;\r
-\r
-            @Override\r
-            public void setImageSize(int width, int height) {\r
-                r = Math.min(width, height) * 0.5f;\r
-                center = new float[]{width * 0.5f, height * 0.5f};\r
-            }\r
-\r
-            @Override\r
-            public byte getAlpha(float x, float y) {\r
-                float d = FastMath.abs(FastMath.sqrt((x - center[0]) * (x - center[0]) + (y - center[1]) * (y - center[1])));\r
-                return (byte) (d >= r ? 0 : -255.0f * d / r + 255.0f);\r
-            }\r
-        });\r
-        alphaMasks.put(ALPHA_MASK_HYPERBOLE, new AlphaMask() {\r
-\r
-            private float r;\r
-            private float[] center;\r
-\r
-            @Override\r
-            public void setImageSize(int width, int height) {\r
-                r = Math.min(width, height) * 0.5f;\r
-                center = new float[]{width * 0.5f, height * 0.5f};\r
-            }\r
-\r
-            @Override\r
-            public byte getAlpha(float x, float y) {\r
-                float d = FastMath.abs(FastMath.sqrt((x - center[0]) * (x - center[0]) + (y - center[1]) * (y - center[1]))) / r;\r
-                return d >= 1.0f ? 0 : (byte) ((-FastMath.sqrt((2.0f - d) * d) + 1.0f) * 255.0f);\r
-            }\r
-        });\r
-    }\r
-\r
-    /**\r
-     * This method sets the face cull mode to be used with every loaded material.\r
-     * \r
-     * @param faceCullMode\r
-     *        the face cull mode\r
-     */\r
-    public void setFaceCullMode(FaceCullMode faceCullMode) {\r
-        this.faceCullMode = faceCullMode;\r
-    }\r
-\r
-    @SuppressWarnings("unchecked")\r
-    public Material toMaterial(Structure structure, DataRepository dataRepository) throws BlenderFileException {\r
-        LOGGER.log(Level.INFO, "Loading material.");\r
-        if (structure == null) {\r
-            return dataRepository.getDefaultMaterial();\r
-        }\r
-        Material result = (Material) dataRepository.getLoadedFeature(structure.getOldMemoryAddress(), LoadedFeatureDataType.LOADED_FEATURE);\r
-        if (result != null) {\r
-            return result;\r
-        }\r
-\r
-        int mode = ((Number) structure.getFieldValue("mode")).intValue();\r
-        boolean shadeless = (mode & 0x4) != 0;\r
-        boolean vertexColor = (mode & 0x16) != 0;\r
-        boolean transparent = (mode & 0x64) != 0;\r
-\r
-        if (shadeless) {\r
-            result = new Material(dataRepository.getAssetManager(), "Common/MatDefs/Misc/Unshaded.j3md");\r
-        } else {\r
-            result = new Material(dataRepository.getAssetManager(), "Common/MatDefs/Light/Lighting.j3md");\r
-        }\r
-\r
-        result.getAdditionalRenderState().setFaceCullMode(faceCullMode);\r
-\r
-        if (transparent) {\r
-            result.getAdditionalRenderState().setBlendMode(BlendMode.Alpha);\r
-        }\r
-\r
-        String name = structure.getName();\r
-        LOGGER.log(Level.INFO, "Material's name: {0}", name);\r
-        if (vertexColor) {\r
-            if (shadeless) {\r
-                result.setBoolean("VertexColor", true);\r
-            } else {\r
-                result.setBoolean("UseVertexColor", true);\r
-            }\r
-        }\r
-\r
-        MaterialHelper materialHelper = dataRepository.getHelper(MaterialHelper.class);\r
-        ColorRGBA diffuseColor = null;\r
-        if (shadeless) {\r
-            // color of shadeless? doesn't seem to work in blender ..\r
-        } else {\r
-            result.setBoolean("UseMaterialColors", true);\r
-\r
-            // setting the colors\r
-            DiffuseShader diffuseShader = materialHelper.getDiffuseShader(structure);\r
-            result.setBoolean("Minnaert", diffuseShader == DiffuseShader.MINNAERT);\r
-            diffuseColor = materialHelper.getDiffuseColor(structure, diffuseShader);\r
-            result.setColor("Diffuse", diffuseColor);\r
-\r
-            SpecularShader specularShader = materialHelper.getSpecularShader(structure);\r
-            result.setBoolean("WardIso", specularShader == SpecularShader.WARDISO);\r
-            result.setColor("Specular", materialHelper.getSpecularColor(structure, specularShader));\r
-\r
-            result.setColor("Ambient", materialHelper.getAmbientColor(structure));\r
-            result.setFloat("Shininess", materialHelper.getShininess(structure));\r
-        }\r
-\r
-        // texture\r
-        if ((dataRepository.getBlenderKey().getFeaturesToLoad() & FeaturesToLoad.TEXTURES) != 0) {\r
-            TextureHelper textureHelper = dataRepository.getHelper(TextureHelper.class);\r
-            DynamicArray<Pointer> mtexs = (DynamicArray<Pointer>) structure.getFieldValue("mtex");\r
-            for (int i = 0; i < mtexs.getTotalSize(); ++i) {\r
-                Pointer p = mtexs.get(i);\r
-                if (!p.isNull()) {\r
-                    List<Structure> mtex = p.fetchData(dataRepository.getInputStream());\r
-                    if (mtex.size() == 1) {\r
-                        Structure textureLink = mtex.get(0);\r
-                        int texflag = ((Number) textureLink.getFieldValue("texflag")).intValue();\r
-                        // int texco = ((Number) textureLink.getFieldValue("texco")).intValue();\r
-                        boolean negateTexture = (texflag & 0x04) == 0;\r
-\r
-                        // if(texco == 0x10) {//TEXCO_UV (this is only supported now)\r
-                        int mapto = ((Number) textureLink.getFieldValue("mapto")).intValue();\r
-                        if (mapto != 0) {\r
-                            Pointer pTex = (Pointer) textureLink.getFieldValue("tex");\r
-                            Structure tex = pTex.fetchData(dataRepository.getInputStream()).get(0);\r
-                            Texture texture = textureHelper.getTexture(tex, dataRepository);\r
-                            if (texture != null) {\r
-                                if ((mapto & 0x01) != 0) {// Col\r
-                                    if (!shadeless){\r
-                                        result.setBoolean("UseMaterialColors", false);\r
-                                    }\r
-                                    \r
-                                    // blending the texture with material color and texture's defined color\r
-                                    int blendType = ((Number) textureLink.getFieldValue("blendtype")).intValue();\r
-                                    float[] color = new float[]{((Number) textureLink.getFieldValue("r")).floatValue(), ((Number) textureLink.getFieldValue("g")).floatValue(), ((Number) textureLink.getFieldValue("b")).floatValue()};\r
-                                    float colfac = ((Number) textureLink.getFieldValue("colfac")).floatValue();\r
-                                    texture = textureHelper.blendTexture(diffuseColor.getColorArray(), texture, color, colfac, blendType, negateTexture, dataRepository);\r
-                                    texture.setWrap(WrapMode.Repeat);\r
-                                    if (shadeless) {\r
-                                        result.setTexture(TEXTURE_TYPE_COLOR, texture);\r
-                                    } else {\r
-                                        result.setTexture(TEXTURE_TYPE_DIFFUSE, texture);\r
-                                    }\r
-                                }\r
-                                if ((mapto & 0x02) != 0) {// Nor\r
-                                    result.setTexture(TEXTURE_TYPE_NORMAL, texture);\r
-                                }\r
-                                if ((mapto & 0x20) != 0) {// Spec\r
-                                    result.setTexture(TEXTURE_TYPE_SPECULAR, texture);\r
-                                }\r
-                                if ((mapto & 0x40) != 0) {// Emit\r
-                                    result.setTexture(TEXTURE_TYPE_GLOW, texture);\r
-                                }\r
-                                if ((mapto & 0x80) != 0) {// Alpha\r
-                                    result.setTexture(TEXTURE_TYPE_ALPHA, texture);\r
-                                }\r
-                            } else {\r
-                                LOGGER.log(Level.WARNING, "Texture not found!");\r
-                            }\r
-                        }\r
-                        // } else {\r
-                        // Pointer pTex = (Pointer)textureLink.getFieldValue("tex");\r
-                        // List<Structure> texs = pTex.fetchData(dataRepository.getInputStream());\r
-                        // Structure tex = texs.get(0);\r
-                        // LOGGER.log(Level.WARNING, "Unsupported texture type: " + texco);\r
-                        // }\r
-                    } else {\r
-                        LOGGER.log(Level.WARNING, "Many textures. Not solved yet!");// TODO\r
-                    }\r
-                }\r
-            }\r
-        }\r
-        dataRepository.addLoadedFeatures(structure.getOldMemoryAddress(), structure.getName(), structure, result);\r
-        return result;\r
-    }\r
-\r
-    /**\r
-     * This method returns a material similar to the one given but without textures. If the material has no textures it is not cloned but\r
-     * returned itself.\r
-     * \r
-     * @param material\r
-     *        a material to be cloned without textures\r
-     * @param imageType\r
-     *        type of image defined by blender; the constants are defined in TextureHelper\r
-     * @return material without textures of a specified type\r
-     */\r
-    public Material getNonTexturedMaterial(Material material, int imageType) {\r
-        String[] textureParamNames = new String[]{TEXTURE_TYPE_DIFFUSE, TEXTURE_TYPE_NORMAL, TEXTURE_TYPE_GLOW, TEXTURE_TYPE_SPECULAR, TEXTURE_TYPE_ALPHA};\r
-        Map<String, Texture> textures = new HashMap<String, Texture>(textureParamNames.length);\r
-        for (String textureParamName : textureParamNames) {\r
-            MatParamTexture matParamTexture = material.getTextureParam(textureParamName);\r
-            if (matParamTexture != null) {\r
-                textures.put(textureParamName, matParamTexture.getTextureValue());\r
-            }\r
-        }\r
-        if (textures.isEmpty()) {\r
-            return material;\r
-        } else {\r
-            // clear all textures first so that wo de not waste resources cloning them\r
-            for (Entry<String, Texture> textureParamName : textures.entrySet()) {\r
-                String name = textureParamName.getValue().getName();\r
-                try {\r
-                    int type = Integer.parseInt(name);\r
-                    if (type == imageType) {\r
-                        material.clearParam(textureParamName.getKey());\r
-                    }\r
-                } catch (NumberFormatException e) {\r
-                    LOGGER.log(Level.WARNING, "The name of the texture does not contain the texture type value! {0} will not be removed!", name);\r
-                }\r
-            }\r
-            Material result = material.clone();\r
-            // put the textures back in place\r
-            for (Entry<String, Texture> textureEntry : textures.entrySet()) {\r
-                material.setTexture(textureEntry.getKey(), textureEntry.getValue());\r
-            }\r
-            return result;\r
-        }\r
-    }\r
-\r
-    /**\r
-     * This method converts the given material into particles-usable material.\r
-     * The texture and glow color are being copied.\r
-     * The method assumes it receives the Lighting type of material.\r
-     * @param material\r
-     *        the source material\r
-     * @param dataRepository\r
-     *        the data repository\r
-     * @return material converted into particles-usable material\r
-     */\r
-    public Material getParticlesMaterial(Material material, Integer alphaMaskIndex, DataRepository dataRepository) {\r
-        Material result = new Material(dataRepository.getAssetManager(), "Common/MatDefs/Misc/Particle.j3md");\r
-\r
-        // copying texture\r
-        MatParam diffuseMap = material.getParam("DiffuseMap");\r
-        if (diffuseMap != null) {\r
-            Texture texture = ((Texture) diffuseMap.getValue()).clone();\r
-\r
-            // applying alpha mask to the texture\r
-            Image image = texture.getImage();\r
-            ByteBuffer sourceBB = image.getData(0);\r
-            sourceBB.rewind();\r
-            int w = image.getWidth();\r
-            int h = image.getHeight();\r
-            ByteBuffer bb = BufferUtils.createByteBuffer(w * h * 4);\r
-            AlphaMask iAlphaMask = alphaMasks.get(alphaMaskIndex);\r
-            iAlphaMask.setImageSize(w, h);\r
-\r
-            for (int x = 0; x < w; ++x) {\r
-                for (int y = 0; y < h; ++y) {\r
-                    bb.put(sourceBB.get());\r
-                    bb.put(sourceBB.get());\r
-                    bb.put(sourceBB.get());\r
-                    bb.put(iAlphaMask.getAlpha(x, y));\r
-                }\r
-            }\r
-\r
-            image = new Image(Format.RGBA8, w, h, bb);\r
-            texture.setImage(image);\r
-\r
-            result.setTextureParam("Texture", VarType.Texture2D, texture);\r
-        }\r
-\r
-        // copying glow color\r
-        MatParam glowColor = material.getParam("GlowColor");\r
-        if (glowColor != null) {\r
-            ColorRGBA color = (ColorRGBA) glowColor.getValue();\r
-            result.setParam("GlowColor", VarType.Vector3, color);\r
-        }\r
-        return result;\r
-    }\r
-\r
-    /**\r
-     * This method indicates if the material has a texture of a specified type.\r
-     * \r
-     * @param material\r
-     *        the material\r
-     * @param textureType\r
-     *        the type of the texture\r
-     * @return <b>true</b> if the texture exists in the material and <B>false</b> otherwise\r
-     */\r
-    public boolean hasTexture(Material material, String textureType) {\r
-        if (material != null) {\r
-            return material.getTextureParam(textureType) != null;\r
-        }\r
-        return false;\r
-    }\r
-\r
-    /**\r
-     * This method returns the diffuse color\r
-     * \r
-     * @param materialStructure\r
-     * @param diffuseShader\r
-     * @return\r
-     */\r
-    public ColorRGBA getDiffuseColor(Structure materialStructure, DiffuseShader diffuseShader) {\r
-        // bitwise 'or' of all textures mappings\r
-        int commonMapto = ((Number) materialStructure.getFieldValue("mapto")).intValue();\r
-\r
-        // diffuse color\r
-        float r = ((Number) materialStructure.getFieldValue("r")).floatValue();\r
-        float g = ((Number) materialStructure.getFieldValue("g")).floatValue();\r
-        float b = ((Number) materialStructure.getFieldValue("b")).floatValue();\r
-        float alpha = ((Number) materialStructure.getFieldValue("alpha")).floatValue();\r
-        if ((commonMapto & 0x01) == 0x01) {// Col\r
-            return new ColorRGBA(r, g, b, alpha);\r
-        } else {\r
-            switch (diffuseShader) {\r
-                case FRESNEL:\r
-                case ORENNAYAR:\r
-                case TOON:\r
-                    break;// TODO: find what is the proper modification\r
-                case MINNAERT:\r
-                case LAMBERT:// TODO: check if that is correct\r
-                    float ref = ((Number) materialStructure.getFieldValue("ref")).floatValue();\r
-                    r *= ref;\r
-                    g *= ref;\r
-                    b *= ref;\r
-                    break;\r
-                default:\r
-                    throw new IllegalStateException("Unknown diffuse shader type: " + diffuseShader.toString());\r
-            }\r
-            return new ColorRGBA(r, g, b, alpha);\r
-        }\r
-    }\r
-\r
-    /**\r
-     * This method returns an enum describing the type of a diffuse shader used by this material.\r
-     * \r
-     * @param materialStructure\r
-     *        the material structure filled with data\r
-     * @return an enum describing the type of a diffuse shader used by this material\r
-     */\r
-    public DiffuseShader getDiffuseShader(Structure materialStructure) {\r
-        int diff_shader = ((Number) materialStructure.getFieldValue("diff_shader")).intValue();\r
-        return DiffuseShader.values()[diff_shader];\r
-    }\r
-\r
-    /**\r
-     * This method returns an ambient color used by the material.\r
-     * \r
-     * @param materialStructure\r
-     *        the material structure filled with data\r
-     * @return an ambient color used by the material\r
-     */\r
-    public ColorRGBA getAmbientColor(Structure materialStructure) {\r
-        float r = ((Number) materialStructure.getFieldValue("ambr")).floatValue();\r
-        float g = ((Number) materialStructure.getFieldValue("ambg")).floatValue();\r
-        float b = ((Number) materialStructure.getFieldValue("ambb")).floatValue();\r
-        float alpha = ((Number) materialStructure.getFieldValue("alpha")).floatValue();\r
-        return new ColorRGBA(r, g, b, alpha);\r
-    }\r
-\r
-    /**\r
-     * This method returns an enum describing the type of a specular shader used by this material.\r
-     * \r
-     * @param materialStructure\r
-     *        the material structure filled with data\r
-     * @return an enum describing the type of a specular shader used by this material\r
-     */\r
-    public SpecularShader getSpecularShader(Structure materialStructure) {\r
-        int spec_shader = ((Number) materialStructure.getFieldValue("spec_shader")).intValue();\r
-        return SpecularShader.values()[spec_shader];\r
-    }\r
-\r
-    /**\r
-     * This method returns a specular color used by the material.\r
-     * \r
-     * @param materialStructure\r
-     *        the material structure filled with data\r
-     * @return a specular color used by the material\r
-     */\r
-    public ColorRGBA getSpecularColor(Structure materialStructure, SpecularShader specularShader) {\r
-        float r = ((Number) materialStructure.getFieldValue("specr")).floatValue();\r
-        float g = ((Number) materialStructure.getFieldValue("specg")).floatValue();\r
-        float b = ((Number) materialStructure.getFieldValue("specb")).floatValue();\r
-        float alpha = ((Number) materialStructure.getFieldValue("alpha")).floatValue();\r
-        switch (specularShader) {\r
-            case BLINN:\r
-            case COOKTORRENCE:\r
-            case TOON:\r
-            case WARDISO:// TODO: find what is the proper modification\r
-                break;\r
-            case PHONG:// TODO: check if that is correct\r
-                float spec = ((Number) materialStructure.getFieldValue("spec")).floatValue();\r
-                r *= spec * 0.5f;\r
-                g *= spec * 0.5f;\r
-                b *= spec * 0.5f;\r
-                break;\r
-            default:\r
-                throw new IllegalStateException("Unknown specular shader type: " + specularShader.toString());\r
-        }\r
-        return new ColorRGBA(r, g, b, alpha);\r
-    }\r
-\r
-    /**\r
-     * This method returns the sihiness of this material or DEFAULT_SHININESS value if not present.\r
-     * \r
-     * @param materialStructure\r
-     *        the material structure filled with data\r
-     * @return the sihiness of this material or DEFAULT_SHININESS value if not present\r
-     */\r
-    public float getShininess(Structure materialStructure) {\r
-        float shininess = ((Number) materialStructure.getFieldValue("emit")).floatValue();\r
-        return shininess > 0.0f ? shininess : DEFAULT_SHININESS;\r
-    }\r
-\r
-    /**\r
-     * This method returns the table of materials connected to the specified structure. The given structure can be of any type (ie. mesh or\r
-     * curve) but needs to have 'mat' field/\r
-     * \r
-     * @param structureWithMaterials\r
-     *        the structure containing the mesh data\r
-     * @param dataRepository\r
-     *        the data repository\r
-     * @return a list of vertices colors, each color belongs to a single vertex\r
-     * @throws BlenderFileException\r
-     *         this exception is thrown when the blend file structure is somehow invalid or corrupted\r
-     */\r
-    public Material[] getMaterials(Structure structureWithMaterials, DataRepository dataRepository) throws BlenderFileException {\r
-        Pointer ppMaterials = (Pointer) structureWithMaterials.getFieldValue("mat");\r
-        Material[] materials = null;\r
-        if (!ppMaterials.isNull()) {\r
-            List<Structure> materialStructures = ppMaterials.fetchData(dataRepository.getInputStream());\r
-            if (materialStructures != null && materialStructures.size() > 0) {\r
-                MaterialHelper materialHelper = dataRepository.getHelper(MaterialHelper.class);\r
-                materials = new Material[materialStructures.size()];\r
-                int i = 0;\r
-                for (Structure s : materialStructures) {\r
-                    Material material = (Material) dataRepository.getLoadedFeature(s.getOldMemoryAddress(), LoadedFeatureDataType.LOADED_FEATURE);\r
-                    if (material == null) {\r
-                        material = materialHelper.toMaterial(s, dataRepository);\r
-                    }\r
-                    materials[i++] = material;\r
-                }\r
-            }\r
-        }\r
-        return materials;\r
-    }\r
-\r
-    /**\r
-     * This method converts rgb values to hsv values.\r
-     * \r
-     * @param rgb\r
-     *        rgb values of the color\r
-     * @param hsv\r
-     *        hsv values of a color (this table contains the result of the transformation)\r
-     */\r
-    public void rgbToHsv(float r, float g, float b, float[] hsv) {\r
-        float cmax = r;\r
-        float cmin = r;\r
-        cmax = g > cmax ? g : cmax;\r
-        cmin = g < cmin ? g : cmin;\r
-        cmax = b > cmax ? b : cmax;\r
-        cmin = b < cmin ? b : cmin;\r
-\r
-        hsv[2] = cmax; /* value */\r
-        if (cmax != 0.0) {\r
-            hsv[1] = (cmax - cmin) / cmax;\r
-        } else {\r
-            hsv[1] = 0.0f;\r
-            hsv[0] = 0.0f;\r
-        }\r
-        if (hsv[1] == 0.0) {\r
-            hsv[0] = -1.0f;\r
-        } else {\r
-            float cdelta = cmax - cmin;\r
-            float rc = (cmax - r) / cdelta;\r
-            float gc = (cmax - g) / cdelta;\r
-            float bc = (cmax - b) / cdelta;\r
-            if (r == cmax) {\r
-                hsv[0] = bc - gc;\r
-            } else if (g == cmax) {\r
-                hsv[0] = 2.0f + rc - bc;\r
-            } else {\r
-                hsv[0] = 4.0f + gc - rc;\r
-            }\r
-            hsv[0] *= 60.0f;\r
-            if (hsv[0] < 0.0f) {\r
-                hsv[0] += 360.0f;\r
-            }\r
-        }\r
-\r
-        hsv[0] /= 360.0f;\r
-        if (hsv[0] < 0.0f) {\r
-            hsv[0] = 0.0f;\r
-        }\r
-    }\r
-\r
-    /**\r
-     * This method converts rgb values to hsv values.\r
-     * \r
-     * @param h\r
-     *        hue\r
-     * @param s\r
-     *        saturation\r
-     * @param v\r
-     *        value\r
-     * @param rgb\r
-     *        rgb result vector (should have 3 elements)\r
-     */\r
-    public void hsvToRgb(float h, float s, float v, float[] rgb) {\r
-        h *= 360.0f;\r
-        if (s == 0.0) {\r
-            rgb[0] = rgb[1] = rgb[2] = v;\r
-        } else {\r
-            if (h == 360) {\r
-                h = 0;\r
-            } else {\r
-                h /= 60;\r
-            }\r
-            int i = (int) Math.floor(h);\r
-            float f = h - i;\r
-            float p = v * (1.0f - s);\r
-            float q = v * (1.0f - s * f);\r
-            float t = v * (1.0f - s * (1.0f - f));\r
-            switch (i) {\r
-                case 0:\r
-                    rgb[0] = v;\r
-                    rgb[1] = t;\r
-                    rgb[2] = p;\r
-                    break;\r
-                case 1:\r
-                    rgb[0] = q;\r
-                    rgb[1] = v;\r
-                    rgb[2] = p;\r
-                    break;\r
-                case 2:\r
-                    rgb[0] = p;\r
-                    rgb[1] = v;\r
-                    rgb[2] = t;\r
-                    break;\r
-                case 3:\r
-                    rgb[0] = p;\r
-                    rgb[1] = q;\r
-                    rgb[2] = v;\r
-                    break;\r
-                case 4:\r
-                    rgb[0] = t;\r
-                    rgb[1] = p;\r
-                    rgb[2] = v;\r
-                    break;\r
-                case 5:\r
-                    rgb[0] = v;\r
-                    rgb[1] = p;\r
-                    rgb[2] = q;\r
-                    break;\r
-            }\r
-        }\r
-    }\r
-\r
-    /**\r
-     * An interface used in calculating alpha mask during particles' texture calculations.\r
-     * @author Marcin Roguski (Kaelthas)\r
-     */\r
-    protected static interface AlphaMask {\r
-\r
-        /**\r
-         * This method sets the size of the texture's image.\r
-         * @param width\r
-         *        the width of the image\r
-         * @param height\r
-         *        the height of the image\r
-         */\r
-        void setImageSize(int width, int height);\r
-\r
-        /**\r
-         * This method returns the alpha value for the specified texture position.\r
-         * @param x\r
-         *        the X coordinate of the texture position\r
-         * @param y\r
-         *        the Y coordinate of the texture position\r
-         * @return the alpha value for the specified texture position\r
-         */\r
-        byte getAlpha(float x, float y);\r
-    }\r
+       private static final Logger                                     LOGGER                                  = Logger.getLogger(MaterialHelper.class.getName());\r
+       protected static final float                            DEFAULT_SHININESS               = 20.0f;\r
+\r
+       public static final String                                      TEXTURE_TYPE_COLOR              = "ColorMap";\r
+       public static final String                                      TEXTURE_TYPE_DIFFUSE    = "DiffuseMap";\r
+       public static final String                                      TEXTURE_TYPE_NORMAL             = "NormalMap";\r
+       public static final String                                      TEXTURE_TYPE_SPECULAR   = "SpecularMap";\r
+       public static final String                                      TEXTURE_TYPE_GLOW               = "GlowMap";\r
+       public static final String                                      TEXTURE_TYPE_ALPHA              = "AlphaMap";\r
+\r
+       public static final Integer                                     ALPHA_MASK_NONE                 = Integer.valueOf(0);\r
+       public static final Integer                                     ALPHA_MASK_CIRCLE               = Integer.valueOf(1);\r
+       public static final Integer                                     ALPHA_MASK_CONE                 = Integer.valueOf(2);\r
+       public static final Integer                                     ALPHA_MASK_HYPERBOLE    = Integer.valueOf(3);\r
+       protected final Map<Integer, IAlphaMask>        alphaMasks                              = new HashMap<Integer, IAlphaMask>();\r
+\r
+       /**\r
+        * The type of the material's diffuse shader.\r
+        */\r
+       public static enum DiffuseShader {\r
+               LAMBERT, ORENNAYAR, TOON, MINNAERT, FRESNEL\r
+       }\r
+\r
+       /**\r
+        * The type of the material's specular shader.\r
+        */\r
+       public static enum SpecularShader {\r
+               COOKTORRENCE, PHONG, BLINN, TOON, WARDISO\r
+       }\r
+\r
+       /** Face cull mode. Should be excplicitly set before this helper is used. */\r
+       protected FaceCullMode  faceCullMode;\r
+\r
+       /**\r
+        * This constructor parses the given blender version and stores the result. Some functionalities may differ in different blender\r
+        * versions.\r
+        * \r
+        * @param blenderVersion\r
+        *        the version read from the blend file\r
+        */\r
+       public MaterialHelper(String blenderVersion) {\r
+               super(blenderVersion);\r
+               // setting alpha masks\r
+               alphaMasks.put(ALPHA_MASK_NONE, new IAlphaMask() {\r
+                       @Override\r
+                       public void setImageSize(int width, int height) {}\r
+\r
+                       @Override\r
+                       public byte getAlpha(float x, float y) {\r
+                               return (byte) 255;\r
+                       }\r
+               });\r
+               alphaMasks.put(ALPHA_MASK_CIRCLE, new IAlphaMask() {\r
+                       private float   r;\r
+                       private float[] center;\r
+\r
+                       @Override\r
+                       public void setImageSize(int width, int height) {\r
+                               r = Math.min(width, height) * 0.5f;\r
+                               center = new float[] { width * 0.5f, height * 0.5f };\r
+                       }\r
+\r
+                       @Override\r
+                       public byte getAlpha(float x, float y) {\r
+                               float d = FastMath.abs(FastMath.sqrt((x - center[0]) * (x - center[0]) + (y - center[1]) * (y - center[1])));\r
+                               return (byte) (d >= r ? 0 : 255);\r
+                       }\r
+               });\r
+               alphaMasks.put(ALPHA_MASK_CONE, new IAlphaMask() {\r
+                       private float   r;\r
+                       private float[] center;\r
+\r
+                       @Override\r
+                       public void setImageSize(int width, int height) {\r
+                               r = Math.min(width, height) * 0.5f;\r
+                               center = new float[] { width * 0.5f, height * 0.5f };\r
+                       }\r
+\r
+                       @Override\r
+                       public byte getAlpha(float x, float y) {\r
+                               float d = FastMath.abs(FastMath.sqrt((x - center[0]) * (x - center[0]) + (y - center[1]) * (y - center[1])));\r
+                               return (byte) (d >= r ? 0 : -255.0f * d / r + 255.0f);\r
+                       }\r
+               });\r
+               alphaMasks.put(ALPHA_MASK_HYPERBOLE, new IAlphaMask() {\r
+                       private float   r;\r
+                       private float[] center;\r
+\r
+                       @Override\r
+                       public void setImageSize(int width, int height) {\r
+                               r = Math.min(width, height) * 0.5f;\r
+                               center = new float[] { width * 0.5f, height * 0.5f };\r
+                       }\r
+\r
+                       @Override\r
+                       public byte getAlpha(float x, float y) {\r
+                               float d = FastMath.abs(FastMath.sqrt((x - center[0]) * (x - center[0]) + (y - center[1]) * (y - center[1]))) / r;\r
+                               return d >= 1.0f ? 0 : (byte) ((-FastMath.sqrt((2.0f - d) * d) + 1.0f) * 255.0f);\r
+                       }\r
+               });\r
+       }\r
+\r
+       /**\r
+        * This method sets the face cull mode to be used with every loaded material.\r
+        * \r
+        * @param faceCullMode\r
+        *        the face cull mode\r
+        */\r
+       public void setFaceCullMode(FaceCullMode faceCullMode) {\r
+               this.faceCullMode = faceCullMode;\r
+       }\r
+\r
+       @SuppressWarnings("unchecked")\r
+       public Material toMaterial(Structure structure, DataRepository dataRepository) throws BlenderFileException {\r
+               LOGGER.log(Level.INFO, "Loading material.");\r
+               if (structure == null) {\r
+                       return dataRepository.getDefaultMaterial();\r
+               }\r
+               Material result = (Material) dataRepository.getLoadedFeature(structure.getOldMemoryAddress(), LoadedFeatureDataType.LOADED_FEATURE);\r
+               if (result != null) {\r
+                       return result;\r
+               }\r
+\r
+               int mode = ((Number) structure.getFieldValue("mode")).intValue();\r
+               boolean shadeless = (mode & 0x4) != 0;\r
+               boolean vertexColor = (mode & 0x16) != 0;\r
+               boolean transparent = (mode & 0x64) != 0;\r
+\r
+               if (shadeless) {\r
+                       result = new Material(dataRepository.getAssetManager(), "Common/MatDefs/Misc/Unshaded.j3md");\r
+               } else {\r
+                       result = new Material(dataRepository.getAssetManager(), "Common/MatDefs/Light/Lighting.j3md");\r
+               }\r
+\r
+               result.getAdditionalRenderState().setFaceCullMode(faceCullMode);\r
+\r
+               if (transparent) {\r
+                       result.getAdditionalRenderState().setBlendMode(BlendMode.Alpha);\r
+               }\r
+\r
+               String name = structure.getName();\r
+               LOGGER.log(Level.INFO, "Material's name: {0}", name);\r
+               if (vertexColor) {\r
+                       result.setBoolean(shadeless ? "VertexColor" : "UseVertexColor", true);\r
+               }\r
+\r
+               MaterialHelper materialHelper = dataRepository.getHelper(MaterialHelper.class);\r
+               ColorRGBA diffuseColor = null;\r
+               if (shadeless) {\r
+                       // color of shadeless? doesn't seem to work in blender ..\r
+               } else {\r
+                       result.setBoolean("UseMaterialColors", Boolean.TRUE);\r
+\r
+                       // setting the colors\r
+                       DiffuseShader diffuseShader = materialHelper.getDiffuseShader(structure);\r
+                       result.setBoolean("Minnaert", diffuseShader == DiffuseShader.MINNAERT);\r
+                       diffuseColor = materialHelper.getDiffuseColor(structure, diffuseShader);\r
+                       result.setColor("Diffuse", diffuseColor);\r
+\r
+                       SpecularShader specularShader = materialHelper.getSpecularShader(structure);\r
+                       result.setBoolean("WardIso", specularShader == SpecularShader.WARDISO);\r
+                       result.setColor("Specular", materialHelper.getSpecularColor(structure, specularShader));\r
+\r
+                       result.setColor("Ambient", materialHelper.getAmbientColor(structure));\r
+                       result.setFloat("Shininess", materialHelper.getShininess(structure));\r
+               }\r
+\r
+               // texture\r
+               if ((dataRepository.getBlenderKey().getFeaturesToLoad() & FeaturesToLoad.TEXTURES) != 0) {\r
+                       TextureHelper textureHelper = dataRepository.getHelper(TextureHelper.class);\r
+                       DynamicArray<Pointer> mtexs = (DynamicArray<Pointer>) structure.getFieldValue("mtex");\r
+                       for (int i = 0; i < mtexs.getTotalSize(); ++i) {\r
+                               Pointer p = mtexs.get(i);\r
+                               if (!p.isNull()) {\r
+                                       List<Structure> mtex = p.fetchData(dataRepository.getInputStream());\r
+                                       if (mtex.size() == 1) {\r
+                                               Structure textureLink = mtex.get(0);\r
+                                               int texflag = ((Number) textureLink.getFieldValue("texflag")).intValue();\r
+                                               // int texco = ((Number) textureLink.getFieldValue("texco")).intValue();\r
+                                               boolean negateTexture = (texflag & 0x04) == 0;\r
+\r
+                                               // if(texco == 0x10) {//TEXCO_UV (this is only supported now)\r
+                                               int mapto = ((Number) textureLink.getFieldValue("mapto")).intValue();\r
+                                               if (mapto != 0) {\r
+                                                       Pointer pTex = (Pointer) textureLink.getFieldValue("tex");\r
+                                                       Structure tex = pTex.fetchData(dataRepository.getInputStream()).get(0);\r
+                                                       Texture texture = textureHelper.getTexture(tex, dataRepository);\r
+                                                       if (texture != null) {\r
+                                                               if ((mapto & 0x01) != 0) {// Col\r
+                                                                       result.setBoolean("UseMaterialColors", Boolean.FALSE);\r
+                                                                       // blending the texture with material color and texture's defined color\r
+                                                                       int blendType = ((Number) textureLink.getFieldValue("blendtype")).intValue();\r
+                                                                       float[] color = new float[] { ((Number) textureLink.getFieldValue("r")).floatValue(), ((Number) textureLink.getFieldValue("g")).floatValue(), ((Number) textureLink.getFieldValue("b")).floatValue() };\r
+                                                                       float colfac = ((Number) textureLink.getFieldValue("colfac")).floatValue();\r
+                                                                       texture = textureHelper.blendTexture(diffuseColor.getColorArray(), texture, color, colfac, blendType, negateTexture, dataRepository);\r
+                                                                       texture.setWrap(WrapMode.Repeat);\r
+                                                                       if (shadeless) {\r
+                                                                               result.setTexture(TEXTURE_TYPE_COLOR, texture);\r
+                                                                       } else {\r
+                                                                               result.setTexture(TEXTURE_TYPE_DIFFUSE, texture);\r
+                                                                       }\r
+                                                               }\r
+                                                               if ((mapto & 0x02) != 0) {// Nor\r
+                                                                       result.setTexture(TEXTURE_TYPE_NORMAL, texture);\r
+                                                                       if (vertexColor) {\r
+                                                                               result.setBoolean(shadeless ? "VertexColor" : "UseVertexColor", false);\r
+                                                                       }\r
+                                                               }\r
+                                                               if ((mapto & 0x04) != 0) {// Spec\r
+                                                                       result.setTexture(TEXTURE_TYPE_SPECULAR, texture);\r
+                                                               }\r
+                                                               if ((mapto & 0x40) != 0) {// Emit\r
+                                                                       result.setTexture(TEXTURE_TYPE_GLOW, texture);\r
+                                                               }\r
+                                                               if ((mapto & 0x80) != 0) {// Alpha\r
+                                                                       result.setTexture(TEXTURE_TYPE_ALPHA, texture);\r
+                                                               }\r
+                                                       } else {\r
+                                                               LOGGER.log(Level.WARNING, "Texture not found!");\r
+                                                       }\r
+                                               }\r
+                                               // } else {\r
+                                               // Pointer pTex = (Pointer)textureLink.getFieldValue("tex");\r
+                                               // List<Structure> texs = pTex.fetchData(dataRepository.getInputStream());\r
+                                               // Structure tex = texs.get(0);\r
+                                               // LOGGER.log(Level.WARNING, "Unsupported texture type: " + texco);\r
+                                               // }\r
+                                       } else {\r
+                                               LOGGER.log(Level.WARNING, "Many textures. Not solved yet!");// TODO\r
+                                       }\r
+                               }\r
+                       }\r
+               }\r
+               dataRepository.addLoadedFeatures(structure.getOldMemoryAddress(), structure.getName(), structure, result);\r
+               return result;\r
+       }\r
+\r
+       /**\r
+        * This method returns a material similar to the one given but without textures. If the material has no textures it is not cloned but\r
+        * returned itself.\r
+        * \r
+        * @param material\r
+        *        a material to be cloned without textures\r
+        * @param imageType\r
+        *        type of image defined by blender; the constants are defined in TextureHelper\r
+        * @return material without textures of a specified type\r
+        */\r
+       public Material getNonTexturedMaterial(Material material, int imageType) {\r
+               String[] textureParamNames = new String[] { TEXTURE_TYPE_DIFFUSE, TEXTURE_TYPE_NORMAL, TEXTURE_TYPE_GLOW, TEXTURE_TYPE_SPECULAR, TEXTURE_TYPE_ALPHA };\r
+               Map<String, Texture> textures = new HashMap<String, Texture>(textureParamNames.length);\r
+               for (String textureParamName : textureParamNames) {\r
+                       MatParamTexture matParamTexture = material.getTextureParam(textureParamName);\r
+                       if (matParamTexture != null) {\r
+                               textures.put(textureParamName, matParamTexture.getTextureValue());\r
+                       }\r
+               }\r
+               if (textures.isEmpty()) {\r
+                       return material;\r
+               } else {\r
+                       // clear all textures first so that wo de not waste resources cloning them\r
+                       for (Entry<String, Texture> textureParamName : textures.entrySet()) {\r
+                               String name = textureParamName.getValue().getName();\r
+                               try {\r
+                                       int type = Integer.parseInt(name);\r
+                                       if (type == imageType) {\r
+                                               material.clearParam(textureParamName.getKey());\r
+                                       }\r
+                               } catch (NumberFormatException e) {\r
+                                       LOGGER.log(Level.WARNING, "The name of the texture does not contain the texture type value! {0} will not be removed!", name);\r
+                               }\r
+                       }\r
+                       Material result = material.clone();\r
+                       // put the textures back in place\r
+                       for (Entry<String, Texture> textureEntry : textures.entrySet()) {\r
+                               material.setTexture(textureEntry.getKey(), textureEntry.getValue());\r
+                       }\r
+                       return result;\r
+               }\r
+       }\r
+\r
+       /**\r
+        * This method converts the given material into particles-usable material.\r
+        * The texture and glow color are being copied.\r
+        * The method assumes it receives the Lighting type of material.\r
+        * @param material\r
+        *        the source material\r
+        * @param dataRepository\r
+        *        the data repository\r
+        * @return material converted into particles-usable material\r
+        */\r
+       public Material getParticlesMaterial(Material material, Integer alphaMaskIndex, DataRepository dataRepository) {\r
+               Material result = new Material(dataRepository.getAssetManager(), "Common/MatDefs/Misc/Particle.j3md");\r
+\r
+               // copying texture\r
+               MatParam diffuseMap = material.getParam("DiffuseMap");\r
+               if (diffuseMap != null) {\r
+                       Texture texture = ((Texture) diffuseMap.getValue()).clone();\r
+\r
+                       // applying alpha mask to the texture\r
+                       Image image = texture.getImage();\r
+                       ByteBuffer sourceBB = image.getData(0);\r
+                       sourceBB.rewind();\r
+                       int w = image.getWidth();\r
+                       int h = image.getHeight();\r
+                       ByteBuffer bb = BufferUtils.createByteBuffer(w * h * 4);\r
+                       IAlphaMask iAlphaMask = alphaMasks.get(alphaMaskIndex);\r
+                       iAlphaMask.setImageSize(w, h);\r
+\r
+                       for (int x = 0; x < w; ++x) {\r
+                               for (int y = 0; y < h; ++y) {\r
+                                       bb.put(sourceBB.get());\r
+                                       bb.put(sourceBB.get());\r
+                                       bb.put(sourceBB.get());\r
+                                       bb.put(iAlphaMask.getAlpha(x, y));\r
+                               }\r
+                       }\r
+\r
+                       image = new Image(Format.RGBA8, w, h, bb);\r
+                       texture.setImage(image);\r
+\r
+                       result.setTextureParam("Texture", VarType.Texture2D, texture);\r
+               }\r
+\r
+               // copying glow color\r
+               MatParam glowColor = material.getParam("GlowColor");\r
+               if (glowColor != null) {\r
+                       ColorRGBA color = (ColorRGBA) glowColor.getValue();\r
+                       result.setParam("GlowColor", VarType.Vector3, color);\r
+               }\r
+               return result;\r
+       }\r
+\r
+       /**\r
+        * This method indicates if the material has a texture of a specified type.\r
+        * \r
+        * @param material\r
+        *        the material\r
+        * @param textureType\r
+        *        the type of the texture\r
+        * @return <b>true</b> if the texture exists in the material and <B>false</b> otherwise\r
+        */\r
+       public boolean hasTexture(Material material, String textureType) {\r
+               if (material != null) {\r
+                       return material.getTextureParam(textureType) != null;\r
+               }\r
+               return false;\r
+       }\r
+\r
+       /**\r
+        * This method returns the diffuse color\r
+        * \r
+        * @param materialStructure\r
+        * @param diffuseShader\r
+        * @return\r
+        */\r
+       public ColorRGBA getDiffuseColor(Structure materialStructure, DiffuseShader diffuseShader) {\r
+               // bitwise 'or' of all textures mappings\r
+               int commonMapto = ((Number) materialStructure.getFieldValue("mapto")).intValue();\r
+\r
+               // diffuse color\r
+               float r = ((Number) materialStructure.getFieldValue("r")).floatValue();\r
+               float g = ((Number) materialStructure.getFieldValue("g")).floatValue();\r
+               float b = ((Number) materialStructure.getFieldValue("b")).floatValue();\r
+               float alpha = ((Number) materialStructure.getFieldValue("alpha")).floatValue();\r
+               if ((commonMapto & 0x01) == 0x01) {// Col\r
+                       return new ColorRGBA(r, g, b, alpha);\r
+               } else {\r
+                       switch (diffuseShader) {\r
+                               case FRESNEL:\r
+                               case ORENNAYAR:\r
+                               case TOON:\r
+                                       break;// TODO: find what is the proper modification\r
+                               case MINNAERT:\r
+                               case LAMBERT:// TODO: check if that is correct\r
+                                       float ref = ((Number) materialStructure.getFieldValue("ref")).floatValue();\r
+                                       r *= ref;\r
+                                       g *= ref;\r
+                                       b *= ref;\r
+                                       break;\r
+                               default:\r
+                                       throw new IllegalStateException("Unknown diffuse shader type: " + diffuseShader.toString());\r
+                       }\r
+                       return new ColorRGBA(r, g, b, alpha);\r
+               }\r
+       }\r
+\r
+       /**\r
+        * This method returns an enum describing the type of a diffuse shader used by this material.\r
+        * \r
+        * @param materialStructure\r
+        *        the material structure filled with data\r
+        * @return an enum describing the type of a diffuse shader used by this material\r
+        */\r
+       public DiffuseShader getDiffuseShader(Structure materialStructure) {\r
+               int diff_shader = ((Number) materialStructure.getFieldValue("diff_shader")).intValue();\r
+               return DiffuseShader.values()[diff_shader];\r
+       }\r
+\r
+       /**\r
+        * This method returns an ambient color used by the material.\r
+        * \r
+        * @param materialStructure\r
+        *        the material structure filled with data\r
+        * @return an ambient color used by the material\r
+        */\r
+       public ColorRGBA getAmbientColor(Structure materialStructure) {\r
+               float r = ((Number) materialStructure.getFieldValue("ambr")).floatValue();\r
+               float g = ((Number) materialStructure.getFieldValue("ambg")).floatValue();\r
+               float b = ((Number) materialStructure.getFieldValue("ambb")).floatValue();\r
+               float alpha = ((Number) materialStructure.getFieldValue("alpha")).floatValue();\r
+               return new ColorRGBA(r, g, b, alpha);\r
+       }\r
+\r
+       /**\r
+        * This method returns an enum describing the type of a specular shader used by this material.\r
+        * \r
+        * @param materialStructure\r
+        *        the material structure filled with data\r
+        * @return an enum describing the type of a specular shader used by this material\r
+        */\r
+       public SpecularShader getSpecularShader(Structure materialStructure) {\r
+               int spec_shader = ((Number) materialStructure.getFieldValue("spec_shader")).intValue();\r
+               return SpecularShader.values()[spec_shader];\r
+       }\r
+\r
+       /**\r
+        * This method returns a specular color used by the material.\r
+        * \r
+        * @param materialStructure\r
+        *        the material structure filled with data\r
+        * @return a specular color used by the material\r
+        */\r
+       public ColorRGBA getSpecularColor(Structure materialStructure, SpecularShader specularShader) {\r
+               float r = ((Number) materialStructure.getFieldValue("specr")).floatValue();\r
+               float g = ((Number) materialStructure.getFieldValue("specg")).floatValue();\r
+               float b = ((Number) materialStructure.getFieldValue("specb")).floatValue();\r
+               float alpha = ((Number) materialStructure.getFieldValue("alpha")).floatValue();\r
+               switch (specularShader) {\r
+                       case BLINN:\r
+                       case COOKTORRENCE:\r
+                       case TOON:\r
+                       case WARDISO:// TODO: find what is the proper modification\r
+                               break;\r
+                       case PHONG:// TODO: check if that is correct\r
+                               float spec = ((Number) materialStructure.getFieldValue("spec")).floatValue();\r
+                               r *= spec * 0.5f;\r
+                               g *= spec * 0.5f;\r
+                               b *= spec * 0.5f;\r
+                               break;\r
+                       default:\r
+                               throw new IllegalStateException("Unknown specular shader type: " + specularShader.toString());\r
+               }\r
+               return new ColorRGBA(r, g, b, alpha);\r
+       }\r
+\r
+       /**\r
+        * This method returns the sihiness of this material or DEFAULT_SHININESS value if not present.\r
+        * \r
+        * @param materialStructure\r
+        *        the material structure filled with data\r
+        * @return the sihiness of this material or DEFAULT_SHININESS value if not present\r
+        */\r
+       public float getShininess(Structure materialStructure) {\r
+               float shininess = ((Number) materialStructure.getFieldValue("emit")).floatValue();\r
+               return shininess > 0.0f ? shininess : DEFAULT_SHININESS;\r
+       }\r
+\r
+       /**\r
+        * This method returns the table of materials connected to the specified structure. The given structure can be of any type (ie. mesh or\r
+        * curve) but needs to have 'mat' field/\r
+        * \r
+        * @param structureWithMaterials\r
+        *        the structure containing the mesh data\r
+        * @param dataRepository\r
+        *        the data repository\r
+        * @return a list of vertices colors, each color belongs to a single vertex\r
+        * @throws BlenderFileException\r
+        *         this exception is thrown when the blend file structure is somehow invalid or corrupted\r
+        */\r
+       public Material[] getMaterials(Structure structureWithMaterials, DataRepository dataRepository) throws BlenderFileException {\r
+               Pointer ppMaterials = (Pointer) structureWithMaterials.getFieldValue("mat");\r
+               Material[] materials = null;\r
+               if (!ppMaterials.isNull()) {\r
+                       List<Structure> materialStructures = ppMaterials.fetchData(dataRepository.getInputStream());\r
+                       if (materialStructures != null && materialStructures.size() > 0) {\r
+                               MaterialHelper materialHelper = dataRepository.getHelper(MaterialHelper.class);\r
+                               materials = new Material[materialStructures.size()];\r
+                               int i = 0;\r
+                               for (Structure s : materialStructures) {\r
+                                       Material material = (Material) dataRepository.getLoadedFeature(s.getOldMemoryAddress(), LoadedFeatureDataType.LOADED_FEATURE);\r
+                                       if (material == null) {\r
+                                               material = materialHelper.toMaterial(s, dataRepository);\r
+                                       }\r
+                                       materials[i++] = material;\r
+                               }\r
+                       }\r
+               }\r
+               return materials;\r
+       }\r
+\r
+       /**\r
+        * This method converts rgb values to hsv values.\r
+        * \r
+        * @param rgb\r
+        *        rgb values of the color\r
+        * @param hsv\r
+        *        hsv values of a color (this table contains the result of the transformation)\r
+        */\r
+       public void rgbToHsv(float r, float g, float b, float[] hsv) {\r
+               float cmax = r;\r
+               float cmin = r;\r
+               cmax = g > cmax ? g : cmax;\r
+               cmin = g < cmin ? g : cmin;\r
+               cmax = b > cmax ? b : cmax;\r
+               cmin = b < cmin ? b : cmin;\r
+\r
+               hsv[2] = cmax; /* value */\r
+               if (cmax != 0.0) {\r
+                       hsv[1] = (cmax - cmin) / cmax;\r
+               } else {\r
+                       hsv[1] = 0.0f;\r
+                       hsv[0] = 0.0f;\r
+               }\r
+               if (hsv[1] == 0.0) {\r
+                       hsv[0] = -1.0f;\r
+               } else {\r
+                       float cdelta = cmax - cmin;\r
+                       float rc = (cmax - r) / cdelta;\r
+                       float gc = (cmax - g) / cdelta;\r
+                       float bc = (cmax - b) / cdelta;\r
+                       if (r == cmax) {\r
+                               hsv[0] = bc - gc;\r
+                       } else if (g == cmax) {\r
+                               hsv[0] = 2.0f + rc - bc;\r
+                       } else {\r
+                               hsv[0] = 4.0f + gc - rc;\r
+                       }\r
+                       hsv[0] *= 60.0f;\r
+                       if (hsv[0] < 0.0f) {\r
+                               hsv[0] += 360.0f;\r
+                       }\r
+               }\r
+\r
+               hsv[0] /= 360.0f;\r
+               if (hsv[0] < 0.0f) {\r
+                       hsv[0] = 0.0f;\r
+               }\r
+       }\r
+\r
+       /**\r
+        * This method converts rgb values to hsv values.\r
+        * \r
+        * @param h\r
+        *        hue\r
+        * @param s\r
+        *        saturation\r
+        * @param v\r
+        *        value\r
+        * @param rgb\r
+        *        rgb result vector (should have 3 elements)\r
+        */\r
+       public void hsvToRgb(float h, float s, float v, float[] rgb) {\r
+               h *= 360.0f;\r
+               if (s == 0.0) {\r
+                       rgb[0] = rgb[1] = rgb[2] = v;\r
+               } else {\r
+                       if (h == 360) {\r
+                               h = 0;\r
+                       } else {\r
+                               h /= 60;\r
+                       }\r
+                       int i = (int) Math.floor(h);\r
+                       float f = h - i;\r
+                       float p = v * (1.0f - s);\r
+                       float q = v * (1.0f - s * f);\r
+                       float t = v * (1.0f - s * (1.0f - f));\r
+                       switch (i) {\r
+                               case 0:\r
+                                       rgb[0] = v;\r
+                                       rgb[1] = t;\r
+                                       rgb[2] = p;\r
+                                       break;\r
+                               case 1:\r
+                                       rgb[0] = q;\r
+                                       rgb[1] = v;\r
+                                       rgb[2] = p;\r
+                                       break;\r
+                               case 2:\r
+                                       rgb[0] = p;\r
+                                       rgb[1] = v;\r
+                                       rgb[2] = t;\r
+                                       break;\r
+                               case 3:\r
+                                       rgb[0] = p;\r
+                                       rgb[1] = q;\r
+                                       rgb[2] = v;\r
+                                       break;\r
+                               case 4:\r
+                                       rgb[0] = t;\r
+                                       rgb[1] = p;\r
+                                       rgb[2] = v;\r
+                                       break;\r
+                               case 5:\r
+                                       rgb[0] = v;\r
+                                       rgb[1] = p;\r
+                                       rgb[2] = q;\r
+                                       break;\r
+                       }\r
+               }\r
+       }\r
+\r
+       /**\r
+        * An interface used in calculating alpha mask during particles' texture calculations.\r
+        * @author Marcin Roguski (Kaelthas)\r
+        */\r
+       protected static interface IAlphaMask {\r
+               /**\r
+                * This method sets the size of the texture's image.\r
+                * @param width\r
+                *        the width of the image\r
+                * @param height\r
+                *        the height of the image\r
+                */\r
+               void setImageSize(int width, int height);\r
+\r
+               /**\r
+                * This method returns the alpha value for the specified texture position.\r
+                * @param x\r
+                *        the X coordinate of the texture position\r
+                * @param y\r
+                *        the Y coordinate of the texture position\r
+                * @return the alpha value for the specified texture position\r
+                */\r
+               byte getAlpha(float x, float y);\r
+       }\r
 }\r
index 0644a93..b55d6e8 100644 (file)
@@ -53,9 +53,9 @@ import com.jme3.scene.VertexBuffer.Type;
 import com.jme3.scene.VertexBuffer.Usage;\r
 import com.jme3.scene.plugins.blender.data.Structure;\r
 import com.jme3.scene.plugins.blender.exception.BlenderFileException;\r
+import com.jme3.scene.plugins.blender.utils.AbstractBlenderHelper;\r
 import com.jme3.scene.plugins.blender.utils.DataRepository;\r
 import com.jme3.scene.plugins.blender.utils.DataRepository.LoadedFeatureDataType;\r
-import com.jme3.scene.plugins.blender.utils.AbstractBlenderHelper;\r
 import com.jme3.scene.plugins.blender.utils.DynamicArray;\r
 import com.jme3.scene.plugins.blender.utils.Pointer;\r
 import com.jme3.texture.Texture;\r
@@ -67,534 +67,531 @@ import com.jme3.util.BufferUtils;
  * @author Marcin Roguski (Kaelthas)\r
  */\r
 public class MeshHelper extends AbstractBlenderHelper {\r
-\r
-    protected static final int MAXIMUM_WEIGHTS_PER_VERTEX = 4; // have no idea why 4, could someone please explain ?\r
-\r
-    /**\r
-     * This constructor parses the given blender version and stores the result. Some functionalities may differ in different blender\r
-     * versions.\r
-     * \r
-     * @param blenderVersion\r
-     *            the version read from the blend file\r
-     */\r
-    public MeshHelper(String blenderVersion) {\r
-        super(blenderVersion);\r
-    }\r
-\r
-    /**\r
-     * This method reads converts the given structure into mesh. The given structure needs to be filled with the appropriate data.\r
-     * \r
-     * @param structure\r
-     *            the structure we read the mesh from\r
-     * @return the mesh feature\r
-     * @throws BlenderFileException\r
-     */\r
-    @SuppressWarnings("unchecked")\r
-    public List<Geometry> toMesh(Structure structure, DataRepository dataRepository) throws BlenderFileException {\r
-        List<Geometry> geometries = (List<Geometry>) dataRepository.getLoadedFeature(structure.getOldMemoryAddress(),\r
-                LoadedFeatureDataType.LOADED_FEATURE);\r
-        if (geometries != null) {\r
-            List<Geometry> copiedGeometries = new ArrayList<Geometry>(geometries.size());\r
-            for (Geometry geometry : geometries) {\r
-                copiedGeometries.add(geometry.clone());\r
-            }\r
-            return copiedGeometries;\r
-        }\r
-\r
-        // helpers\r
-        TextureHelper textureHelper = dataRepository.getHelper(TextureHelper.class);\r
-\r
-        // reading mesh data\r
-        String name = structure.getName();\r
-\r
-        // reading vertices\r
-        Vector3f[] vertices = this.getVertices(structure, dataRepository);\r
-        int verticesAmount = vertices.length;\r
-\r
-        // vertices Colors\r
-        List<float[]> verticesColors = this.getVerticesColors(structure, dataRepository);\r
-\r
-        // reading faces\r
-        // the following map sorts faces by material number (because in jme Mesh can have only one material)\r
-        Map<Integer, List<Integer>> meshesMap = new HashMap<Integer, List<Integer>>();\r
-        Pointer pMFace = (Pointer) structure.getFieldValue("mface");\r
-        List<Structure> mFaces = pMFace.fetchData(dataRepository.getInputStream());\r
-\r
-        Pointer pMTFace = (Pointer) structure.getFieldValue("mtface");\r
-        List<Vector2f> uvCoordinates = null;\r
-        List<Structure> mtFaces = null;\r
-\r
-        if (!pMTFace.isNull()) {\r
-            mtFaces = pMTFace.fetchData(dataRepository.getInputStream());\r
-            int facesAmount = ((Number) structure.getFieldValue("totface")).intValue();\r
-            if (mtFaces.size() != facesAmount) {\r
-                throw new BlenderFileException("The amount of faces uv coordinates is not equal to faces amount!");\r
-            }\r
-            uvCoordinates = new ArrayList<Vector2f>();// TODO: calculate the amount of coordinates if possible\r
-        }\r
-\r
-        // normalMap merges normals of faces that will be rendered smooth\r
-        Map<Vector3f, Vector3f> normalMap = new HashMap<Vector3f, Vector3f>(verticesAmount);\r
-\r
-        List<Vector3f> normalList = new ArrayList<Vector3f>();\r
-        List<Vector3f> vertexList = new ArrayList<Vector3f>();\r
-        Map<Integer, Texture> materialNumberToTexture = new HashMap<Integer, Texture>();// indicates if the material with the specified\r
-        // number should have a texture attached\r
-        // this map's key is the vertex index from 'vertices 'table and the value are indices from 'vertexList'\r
-        // positions (it simply tells which vertex is referenced where in the result list)\r
-        Map<Integer, List<Integer>> vertexReferenceMap = new HashMap<Integer, List<Integer>>(verticesAmount);\r
-        int vertexColorIndex = 0;\r
-        for (int i = 0; i < mFaces.size(); ++i) {\r
-            Structure mFace = mFaces.get(i);\r
-            boolean smooth = (((Number) mFace.getFieldValue("flag")).byteValue() & 0x01) != 0x00;\r
-            DynamicArray<Number> uvs = null;\r
-            boolean materialWithoutTextures = false;\r
-            Pointer pImage = null;\r
-            if (mtFaces != null) {\r
-                Structure mtFace = mtFaces.get(i);\r
-                pImage = (Pointer) mtFace.getFieldValue("tpage");\r
-                materialWithoutTextures = pImage.isNull();\r
-                // uvs always must be added wheater we have texture or not\r
-                uvs = (DynamicArray<Number>) mtFace.getFieldValue("uv");\r
-                uvCoordinates.add(new Vector2f(uvs.get(0, 0).floatValue(), uvs.get(0, 1).floatValue()));\r
-                uvCoordinates.add(new Vector2f(uvs.get(1, 0).floatValue(), uvs.get(1, 1).floatValue()));\r
-                uvCoordinates.add(new Vector2f(uvs.get(2, 0).floatValue(), uvs.get(2, 1).floatValue()));\r
-            }\r
-            int matNr = ((Number) mFace.getFieldValue("mat_nr")).intValue();\r
-            Integer materialNumber = Integer.valueOf(materialWithoutTextures ? -1 * matNr - 1 : matNr);\r
-            List<Integer> indexList = meshesMap.get(materialNumber);\r
-            if (indexList == null) {\r
-                indexList = new ArrayList<Integer>();\r
-                meshesMap.put(materialNumber, indexList);\r
-            }\r
-            if (pImage != null && !pImage.isNull() && !materialNumberToTexture.containsKey(materialNumber)) {// attaching image to texture\r
-                // (face can have UV's and\r
-                // image whlie its material\r
-                // may have no texture\r
-                // attached)\r
-                Texture texture = textureHelper.getTextureFromImage(pImage.fetchData(dataRepository.getInputStream()).get(0),\r
-                        dataRepository);\r
-                if (texture != null) {\r
-                    materialNumberToTexture.put(materialNumber, texture);\r
-                }\r
-            }\r
-\r
-            int v1 = ((Number) mFace.getFieldValue("v1")).intValue();\r
-            int v2 = ((Number) mFace.getFieldValue("v2")).intValue();\r
-            int v3 = ((Number) mFace.getFieldValue("v3")).intValue();\r
-            int v4 = ((Number) mFace.getFieldValue("v4")).intValue();\r
-\r
-            Vector3f n = FastMath.computeNormal(vertices[v1], vertices[v2], vertices[v3]);\r
-            this.addNormal(n, normalMap, smooth, vertices[v1], vertices[v2], vertices[v3]);\r
-            normalList.add(normalMap.get(vertices[v1]));\r
-            normalList.add(normalMap.get(vertices[v2]));\r
-            normalList.add(normalMap.get(vertices[v3]));\r
-\r
-            this.appendVertexReference(v1, vertexList.size(), vertexReferenceMap);\r
-            indexList.add(vertexList.size());\r
-            vertexList.add(vertices[v1]);\r
-\r
-            this.appendVertexReference(v2, vertexList.size(), vertexReferenceMap);\r
-            indexList.add(vertexList.size());\r
-            vertexList.add(vertices[v2]);\r
-\r
-            this.appendVertexReference(v3, vertexList.size(), vertexReferenceMap);\r
-            indexList.add(vertexList.size());\r
-            vertexList.add(vertices[v3]);\r
-\r
-            if (v4 > 0) {\r
-                if (uvs != null) {\r
-                    uvCoordinates.add(new Vector2f(uvs.get(0, 0).floatValue(), uvs.get(0, 1).floatValue()));\r
-                    uvCoordinates.add(new Vector2f(uvs.get(2, 0).floatValue(), uvs.get(2, 1).floatValue()));\r
-                    uvCoordinates.add(new Vector2f(uvs.get(3, 0).floatValue(), uvs.get(3, 1).floatValue()));\r
-                }\r
-                this.appendVertexReference(v1, vertexList.size(), vertexReferenceMap);\r
-                indexList.add(vertexList.size());\r
-                vertexList.add(vertices[v1]);\r
-\r
-                this.appendVertexReference(v3, vertexList.size(), vertexReferenceMap);\r
-                indexList.add(vertexList.size());\r
-                vertexList.add(vertices[v3]);\r
-\r
-                this.appendVertexReference(v4, vertexList.size(), vertexReferenceMap);\r
-                indexList.add(vertexList.size());\r
-                vertexList.add(vertices[v4]);\r
-\r
-                this.addNormal(n, normalMap, smooth, vertices[v4]);\r
-                normalList.add(normalMap.get(vertices[v1]));\r
-                normalList.add(normalMap.get(vertices[v3]));\r
-                normalList.add(normalMap.get(vertices[v4]));\r
-\r
-                if (verticesColors != null) {\r
-                    verticesColors.add(vertexColorIndex + 3, verticesColors.get(vertexColorIndex));\r
-                    verticesColors.add(vertexColorIndex + 4, verticesColors.get(vertexColorIndex + 2));\r
-                }\r
-                vertexColorIndex += 6;\r
-            } else {\r
-                if (verticesColors != null) {\r
-                    verticesColors.remove(vertexColorIndex + 3);\r
-                    vertexColorIndex += 3;\r
-                }\r
-            }\r
-        }\r
-        Vector3f[] normals = normalList.toArray(new Vector3f[normalList.size()]);\r
-\r
-        // reading vertices groups (from the parent)\r
-        Structure parent = dataRepository.peekParent();\r
-        Structure defbase = (Structure) parent.getFieldValue("defbase");\r
-        List<Structure> defs = defbase.evaluateListBase(dataRepository);\r
-        String[] verticesGroups = new String[defs.size()];\r
-        int defIndex = 0;\r
-        for (Structure def : defs) {\r
-            verticesGroups[defIndex++] = def.getFieldValue("name").toString();\r
-        }\r
-\r
-        // vertices bone weights and indices\r
-        ArmatureHelper armatureHelper = dataRepository.getHelper(ArmatureHelper.class);\r
-        Structure defBase = (Structure) parent.getFieldValue("defbase");\r
-        Map<Integer, Integer> groupToBoneIndexMap = armatureHelper.getGroupToBoneIndexMap(defBase, dataRepository);\r
-\r
-        VertexBuffer verticesWeights = null, verticesWeightsIndices = null;\r
-        int[] bonesGroups = new int[]{0};\r
-        VertexBuffer[] boneWeightsAndIndex = this.getBoneWeightAndIndexBuffer(structure, vertexList.size(), bonesGroups,\r
-                vertexReferenceMap, groupToBoneIndexMap, dataRepository);\r
-        verticesWeights = boneWeightsAndIndex[0];\r
-        verticesWeightsIndices = boneWeightsAndIndex[1];\r
-\r
-        // reading materials\r
-        MaterialHelper materialHelper = dataRepository.getHelper(MaterialHelper.class);\r
-        Material[] materials = null;\r
-        Material[] nonTexturedMaterials = null;\r
-        if ((dataRepository.getBlenderKey().getFeaturesToLoad() & FeaturesToLoad.MATERIALS) != 0) {\r
-            materials = materialHelper.getMaterials(structure, dataRepository);\r
-            nonTexturedMaterials = materials == null ? null : new Material[materials.length];// fill it when needed\r
-        }\r
-\r
-        // creating the result meshes\r
-        geometries = new ArrayList<Geometry>(meshesMap.size());\r
-\r
-        VertexBuffer verticesBuffer = new VertexBuffer(Type.Position);\r
-        verticesBuffer.setupData(Usage.Stream, 3, Format.Float,\r
-                BufferUtils.createFloatBuffer(vertexList.toArray(new Vector3f[vertexList.size()])));\r
-\r
-        // initial vertex position (used with animation)\r
-        VertexBuffer verticesBind = new VertexBuffer(Type.BindPosePosition);\r
-        verticesBind.setupData(Usage.CpuOnly, 3, Format.Float, BufferUtils.clone(verticesBuffer.getData()));\r
-\r
-        VertexBuffer normalsBuffer = new VertexBuffer(Type.Normal);\r
-        normalsBuffer.setupData(Usage.Stream, 3, Format.Float, BufferUtils.createFloatBuffer(normals));\r
-\r
-        // initial normals position (used with animation)\r
-        VertexBuffer normalsBind = new VertexBuffer(Type.BindPoseNormal);\r
-        normalsBind.setupData(Usage.CpuOnly, 3, Format.Float, BufferUtils.clone(normalsBuffer.getData()));\r
-\r
-        VertexBuffer uvCoordsBuffer = null;\r
-        if (uvCoordinates != null) {\r
-            uvCoordsBuffer = new VertexBuffer(Type.TexCoord);\r
-            uvCoordsBuffer.setupData(Usage.Static, 2, Format.Float,\r
-                    BufferUtils.createFloatBuffer(uvCoordinates.toArray(new Vector2f[uvCoordinates.size()])));\r
-        }\r
-\r
-        // generating meshes\r
-        FloatBuffer verticesColorsBuffer = this.createFloatBuffer(verticesColors);\r
-        for (Entry<Integer, List<Integer>> meshEntry : meshesMap.entrySet()) {\r
-            Mesh mesh = new Mesh();\r
-\r
-            // creating vertices indices for this mesh\r
-            List<Integer> indexList = meshEntry.getValue();\r
-            short[] indices = new short[indexList.size()];//TODO: check if the model doesn't have more than 32767 vertices\r
-            for (int i = 0; i < indexList.size(); ++i) {//if yes then mesh.getVertices method must be changed to accept other than ShortBuffer\r
-                indices[i] = indexList.get(i).shortValue();\r
-            }\r
-\r
-            // setting vertices\r
-            mesh.setBuffer(Type.Index, 1, BufferUtils.createShortBuffer(indices));\r
-            mesh.setBuffer(verticesBuffer);\r
-            mesh.setBuffer(verticesBind);\r
-\r
-            // setting vertices colors\r
-            if (verticesColorsBuffer != null) {\r
-                mesh.setBuffer(Type.Color, 4, verticesColorsBuffer);\r
-            }\r
-\r
-            // setting weights for bones\r
-            if (verticesWeights != null) {\r
-                mesh.setMaxNumWeights(bonesGroups[0]);\r
-                mesh.setBuffer(verticesWeights);\r
-                mesh.setBuffer(verticesWeightsIndices);\r
-            }\r
-\r
-            // setting faces' normals\r
-            mesh.setBuffer(normalsBuffer);\r
-            mesh.setBuffer(normalsBind);\r
-\r
-            // setting uvCoords\r
-            if (uvCoordsBuffer != null) {\r
-                mesh.setBuffer(uvCoordsBuffer);\r
-            }\r
-\r
-            // creating the result\r
-            Geometry geometry = new Geometry(name + (geometries.size() + 1), mesh);\r
-            if (materials != null) {\r
-                int materialNumber = meshEntry.getKey().intValue();\r
-                Material material;\r
-                if (materialNumber >= 0) {\r
-                    material = materials[materialNumber];\r
-                    if (materialNumberToTexture.containsKey(Integer.valueOf(materialNumber))) {\r
-                        if (material.getMaterialDef().getAssetName().contains("Lighting")) {\r
-                            if (!materialHelper.hasTexture(material, MaterialHelper.TEXTURE_TYPE_DIFFUSE)) {\r
-                                material = material.clone();\r
-                                material.setTexture(MaterialHelper.TEXTURE_TYPE_DIFFUSE,\r
-                                        materialNumberToTexture.get(Integer.valueOf(materialNumber)));\r
-                            }\r
-                        } else {\r
-                            if (!materialHelper.hasTexture(material, MaterialHelper.TEXTURE_TYPE_COLOR)) {\r
-                                material = material.clone();\r
-                                material.setTexture(MaterialHelper.TEXTURE_TYPE_COLOR,\r
-                                        materialNumberToTexture.get(Integer.valueOf(materialNumber)));\r
-                            }\r
-                        }\r
-                    }\r
-                } else {\r
-                    materialNumber = -1 * (materialNumber + 1);\r
-                    if (nonTexturedMaterials[materialNumber] == null) {\r
-                        nonTexturedMaterials[materialNumber] = materialHelper.getNonTexturedMaterial(materials[materialNumber],\r
-                                TextureHelper.TEX_IMAGE);\r
-                    }\r
-                    material = nonTexturedMaterials[materialNumber];\r
-                }\r
-                geometry.setMaterial(material);\r
-            } else {\r
-                geometry.setMaterial(dataRepository.getDefaultMaterial());\r
-            }\r
-            geometries.add(geometry);\r
-        }\r
-        dataRepository.addLoadedFeatures(structure.getOldMemoryAddress(), structure.getName(), structure, geometries);\r
-        return geometries;\r
-    }\r
-\r
-    /**\r
-     * This method adds a normal to a normals' map. This map is used to merge normals of a vertor that should be rendered smooth.\r
-     * \r
-     * @param normalToAdd\r
-     *            a normal to be added\r
-     * @param normalMap\r
-     *            merges normals of faces that will be rendered smooth; the key is the vertex and the value - its normal vector\r
-     * @param smooth\r
-     *            the variable that indicates wheather to merge normals (creating the smooth mesh) or not\r
-     * @param vertices\r
-     *            a list of vertices read from the blender file\r
-     */\r
-    protected void addNormal(Vector3f normalToAdd, Map<Vector3f, Vector3f> normalMap, boolean smooth, Vector3f... vertices) {\r
-        for (Vector3f v : vertices) {\r
-            Vector3f n = normalMap.get(v);\r
-            if (!smooth || n == null) {\r
-                normalMap.put(v, normalToAdd.clone());\r
-            } else {\r
-                n.addLocal(normalToAdd).normalizeLocal();\r
-            }\r
-        }\r
-    }\r
-\r
-    /**\r
-     * This method fills the vertex reference map. The vertices are loaded once and referenced many times in the model. This map is created\r
-     * 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\r
-     * - the reference indices list.\r
-     * \r
-     * @param basicVertexIndex\r
-     *            the index of the vertex from its basic table\r
-     * @param resultIndex\r
-     *            the index of the vertex in its result vertex list\r
-     * @param vertexReferenceMap\r
-     *            the reference map\r
-     */\r
-    protected void appendVertexReference(int basicVertexIndex, int resultIndex, Map<Integer, List<Integer>> vertexReferenceMap) {\r
-        List<Integer> referenceList = vertexReferenceMap.get(Integer.valueOf(basicVertexIndex));\r
-        if (referenceList == null) {\r
-            referenceList = new ArrayList<Integer>();\r
-            vertexReferenceMap.put(Integer.valueOf(basicVertexIndex), referenceList);\r
-        }\r
-        referenceList.add(Integer.valueOf(resultIndex));\r
-    }\r
-\r
-    /**\r
-     * This method returns the vertices colors. Each vertex is stored in float[4] array.\r
-     * \r
-     * @param meshStructure\r
-     *            the structure containing the mesh data\r
-     * @param dataRepository\r
-     *            the data repository\r
-     * @return a list of vertices colors, each color belongs to a single vertex\r
-     * @throws BlenderFileException\r
-     *             this exception is thrown when the blend file structure is somehow invalid or corrupted\r
-     */\r
-    public List<float[]> getVerticesColors(Structure meshStructure, DataRepository dataRepository) throws BlenderFileException {\r
-        Pointer pMCol = (Pointer) meshStructure.getFieldValue("mcol");\r
-        List<float[]> verticesColors = null;\r
-        List<Structure> mCol = null;\r
-        if (!pMCol.isNull()) {\r
-            verticesColors = new LinkedList<float[]>();\r
-            mCol = pMCol.fetchData(dataRepository.getInputStream());\r
-            for (Structure color : mCol) {\r
-                float r = ((Number) color.getFieldValue("r")).byteValue() / 256.0f;\r
-                float g = ((Number) color.getFieldValue("g")).byteValue() / 256.0f;\r
-                float b = ((Number) color.getFieldValue("b")).byteValue() / 256.0f;\r
-                float a = ((Number) color.getFieldValue("a")).byteValue() / 256.0f;\r
-                verticesColors.add(new float[]{b, g, r, a});\r
-            }\r
-        }\r
-        return verticesColors;\r
-    }\r
-\r
-    /**\r
-     * This method returns the vertices.\r
-     * \r
-     * @param meshStructure\r
-     *            the structure containing the mesh data\r
-     * @param dataRepository\r
-     *            the data repository\r
-     * @return a list of vertices colors, each color belongs to a single vertex\r
-     * @throws BlenderFileException\r
-     *             this exception is thrown when the blend file structure is somehow invalid or corrupted\r
-     */\r
-    @SuppressWarnings("unchecked")\r
-    public Vector3f[] getVertices(Structure meshStructure, DataRepository dataRepository) throws BlenderFileException {\r
-        int verticesAmount = ((Number) meshStructure.getFieldValue("totvert")).intValue();\r
-        Vector3f[] vertices = new Vector3f[verticesAmount];\r
-        Pointer pMVert = (Pointer) meshStructure.getFieldValue("mvert");\r
-        List<Structure> mVerts = pMVert.fetchData(dataRepository.getInputStream());\r
-        for (int i = 0; i < verticesAmount; ++i) {\r
-            DynamicArray<Number> coordinates = (DynamicArray<Number>) mVerts.get(i).getFieldValue("co");\r
-            vertices[i] = new Vector3f(coordinates.get(0).floatValue(), coordinates.get(1).floatValue(), coordinates.get(2).floatValue());\r
-        }\r
-        return vertices;\r
-    }\r
-\r
-    /**\r
-     * 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\r
-     * second element is a vertex buffer holding bone indices for vertices (the indices of bones the vertices are assigned to).\r
-     * \r
-     * @param meshStructure\r
-     *            the mesh structure object\r
-     * @param vertexListSize\r
-     *            a number of vertices in the model\r
-     * @param bonesGroups\r
-     *            this is an output parameter, it should be a one-sized array; the maximum amount of weights per vertex (up to\r
-     *            MAXIMUM_WEIGHTS_PER_VERTEX) is stored there\r
-     * @param vertexReferenceMap\r
-     *            this reference map allows to map the original vertices read from blender to vertices that are really in the model; one\r
-     *            vertex may appear several times in the result model\r
-     * @param groupToBoneIndexMap\r
-     *            this object maps the group index (to which a vertices in blender belong) to bone index of the model\r
-     * @param dataRepository\r
-     *            the data repository\r
-     * @return arrays of vertices weights and their bone indices and (as an outpot parameter) the maximum amount of weights for a vertex\r
-     * @throws BlenderFileException\r
-     *             this exception is thrown when the blend file structure is somehow invalid or corrupted\r
-     */\r
-    public VertexBuffer[] getBoneWeightAndIndexBuffer(Structure meshStructure, int vertexListSize, int[] bonesGroups,\r
-            Map<Integer, List<Integer>> vertexReferenceMap, Map<Integer, Integer> groupToBoneIndexMap, DataRepository dataRepository)\r
-            throws BlenderFileException {\r
-        Pointer pDvert = (Pointer) meshStructure.getFieldValue("dvert");// dvert = DeformVERTices\r
-        FloatBuffer weightsFloatData = BufferUtils.createFloatBuffer(vertexListSize * MAXIMUM_WEIGHTS_PER_VERTEX);\r
-        ByteBuffer indicesData = BufferUtils.createByteBuffer(vertexListSize * MAXIMUM_WEIGHTS_PER_VERTEX);\r
-        if (!pDvert.isNull()) {// assigning weights and bone indices\r
-            List<Structure> dverts = pDvert.fetchData(dataRepository.getInputStream());// dverts.size() == verticesAmount (one dvert per\r
-            // vertex in blender)\r
-            int vertexIndex = 0;\r
-            for (Structure dvert : dverts) {\r
-                int totweight = ((Number) dvert.getFieldValue("totweight")).intValue();// total amount of weights assignet to the vertex\r
-                // (max. 4 in JME)\r
-                Pointer pDW = (Pointer) dvert.getFieldValue("dw");\r
-                List<Integer> vertexIndices = vertexReferenceMap.get(Integer.valueOf(vertexIndex));// we fetch the referenced vertices here\r
-                if (totweight > 0 && !pDW.isNull()) {// pDW should never be null here, but I check it just in case :)\r
-                    int weightIndex = 0;\r
-                    List<Structure> dw = pDW.fetchData(dataRepository.getInputStream());\r
-                    for (Structure deformWeight : dw) {\r
-                        Integer boneIndex = groupToBoneIndexMap.get(((Number) deformWeight.getFieldValue("def_nr")).intValue());\r
-                        if (boneIndex != null) {// null here means that we came accross group that has no bone attached to\r
-                            float weight = ((Number) deformWeight.getFieldValue("weight")).floatValue();\r
-                            if (weight == 0.0f) {\r
-                                weight = 1;\r
-                                boneIndex = Integer.valueOf(0);\r
-                            }\r
-                            // we apply the weight to all referenced vertices\r
-                            for (Integer index : vertexIndices) {\r
-                                // all indices are always assigned to 0-indexed bone\r
-                                // weightsFloatData.put(index * MAXIMUM_WEIGHTS_PER_VERTEX + weightIndex, 1.0f);\r
-                                // indicesData.put(index * MAXIMUM_WEIGHTS_PER_VERTEX + weightIndex, (byte)0);\r
-                                // if(weight != 0.0f) {\r
-                                weightsFloatData.put(index * MAXIMUM_WEIGHTS_PER_VERTEX + weightIndex, weight);\r
-                                indicesData.put(index * MAXIMUM_WEIGHTS_PER_VERTEX + weightIndex, boneIndex.byteValue());\r
-                                // }\r
-                            }\r
-                        }\r
-                        ++weightIndex;\r
-                    }\r
-                } else {\r
-                    for (Integer index : vertexIndices) {\r
-                        weightsFloatData.put(index * MAXIMUM_WEIGHTS_PER_VERTEX, 1.0f);\r
-                        indicesData.put(index * MAXIMUM_WEIGHTS_PER_VERTEX, (byte) 0);\r
-                    }\r
-                }\r
-                ++vertexIndex;\r
-            }\r
-        } else {\r
-            // always bind all vertices to 0-indexed bone\r
-            // this bone makes the model look normally if vertices have no bone assigned\r
-            // and it is used in object animation, so if we come accross object animation\r
-            // we can use the 0-indexed bone for this\r
-            for (List<Integer> vertexIndexList : vertexReferenceMap.values()) {\r
-                // we apply the weight to all referenced vertices\r
-                for (Integer index : vertexIndexList) {\r
-                    weightsFloatData.put(index * MAXIMUM_WEIGHTS_PER_VERTEX, 1.0f);\r
-                    indicesData.put(index * MAXIMUM_WEIGHTS_PER_VERTEX, (byte) 0);\r
-                }\r
-            }\r
-        }\r
-\r
-        bonesGroups[0] = this.endBoneAssigns(vertexListSize, weightsFloatData);\r
-        VertexBuffer verticesWeights = new VertexBuffer(Type.BoneWeight);\r
-        verticesWeights.setupData(Usage.CpuOnly, bonesGroups[0], Format.Float, weightsFloatData);\r
-\r
-        VertexBuffer verticesWeightsIndices = new VertexBuffer(Type.BoneIndex);\r
-        verticesWeightsIndices.setupData(Usage.CpuOnly, bonesGroups[0], Format.UnsignedByte, indicesData);\r
-        return new VertexBuffer[]{verticesWeights, verticesWeightsIndices};\r
-    }\r
-\r
-    /**\r
-     * Normalizes weights if needed and finds largest amount of weights used for all vertices in the buffer.\r
-     */\r
-    protected int endBoneAssigns(int vertCount, FloatBuffer weightsFloatData) {\r
-        int maxWeightsPerVert = 0;\r
-        weightsFloatData.rewind();\r
-        for (int v = 0; v < vertCount; ++v) {\r
-            float w0 = weightsFloatData.get(), w1 = weightsFloatData.get(), w2 = weightsFloatData.get(), w3 = weightsFloatData.get();\r
-\r
-            if (w3 != 0) {\r
-                maxWeightsPerVert = Math.max(maxWeightsPerVert, 4);\r
-            } else if (w2 != 0) {\r
-                maxWeightsPerVert = Math.max(maxWeightsPerVert, 3);\r
-            } else if (w1 != 0) {\r
-                maxWeightsPerVert = Math.max(maxWeightsPerVert, 2);\r
-            } else if (w0 != 0) {\r
-                maxWeightsPerVert = Math.max(maxWeightsPerVert, 1);\r
-            }\r
-\r
-            float sum = w0 + w1 + w2 + w3;\r
-            if (sum != 1f && sum != 0.0f) {\r
-                weightsFloatData.position(weightsFloatData.position() - 4);\r
-                // compute new vals based on sum\r
-                float sumToB = 1f / sum;\r
-                weightsFloatData.put(w0 * sumToB);\r
-                weightsFloatData.put(w1 * sumToB);\r
-                weightsFloatData.put(w2 * sumToB);\r
-                weightsFloatData.put(w3 * sumToB);\r
-            }\r
-        }\r
-        weightsFloatData.rewind();\r
-\r
-        // mesh.setMaxNumWeights(maxWeightsPerVert);\r
-        return maxWeightsPerVert;\r
-    }\r
+       protected static final int      MAXIMUM_WEIGHTS_PER_VERTEX      = 4;    // have no idea why 4, could someone please explain ?\r
+\r
+       /**\r
+        * This constructor parses the given blender version and stores the result. Some functionalities may differ in different blender\r
+        * versions.\r
+        * \r
+        * @param blenderVersion\r
+        *            the version read from the blend file\r
+        */\r
+       public MeshHelper(String blenderVersion) {\r
+               super(blenderVersion);\r
+       }\r
+\r
+       /**\r
+        * This method reads converts the given structure into mesh. The given structure needs to be filled with the appropriate data.\r
+        * \r
+        * @param structure\r
+        *            the structure we read the mesh from\r
+        * @return the mesh feature\r
+        * @throws BlenderFileException\r
+        */\r
+       @SuppressWarnings("unchecked")\r
+       public List<Geometry> toMesh(Structure structure, DataRepository dataRepository) throws BlenderFileException {\r
+               List<Geometry> geometries = (List<Geometry>) dataRepository.getLoadedFeature(structure.getOldMemoryAddress(),\r
+                               LoadedFeatureDataType.LOADED_FEATURE);\r
+               if (geometries != null) {\r
+                       List<Geometry> copiedGeometries = new ArrayList<Geometry>(geometries.size());\r
+                       for (Geometry geometry : geometries) {\r
+                               copiedGeometries.add(geometry.clone());\r
+                       }\r
+                       return copiedGeometries;\r
+               }\r
+\r
+               // helpers\r
+               TextureHelper textureHelper = dataRepository.getHelper(TextureHelper.class);\r
+\r
+               // reading mesh data\r
+               String name = structure.getName();\r
+\r
+               // reading vertices\r
+               Vector3f[] vertices = this.getVertices(structure, dataRepository);\r
+               int verticesAmount = vertices.length;\r
+\r
+               // vertices Colors\r
+               List<float[]> verticesColors = this.getVerticesColors(structure, dataRepository);\r
+\r
+               // reading faces\r
+               // the following map sorts faces by material number (because in jme Mesh can have only one material)\r
+               Map<Integer, List<Integer>> meshesMap = new HashMap<Integer, List<Integer>>();\r
+               Pointer pMFace = (Pointer) structure.getFieldValue("mface");\r
+               List<Structure> mFaces = pMFace.fetchData(dataRepository.getInputStream());\r
+\r
+               Pointer pMTFace = (Pointer) structure.getFieldValue("mtface");\r
+               List<Vector2f> uvCoordinates = null;\r
+               List<Structure> mtFaces = null;\r
+\r
+               if (!pMTFace.isNull()) {\r
+                       mtFaces = pMTFace.fetchData(dataRepository.getInputStream());\r
+                       int facesAmount = ((Number) structure.getFieldValue("totface")).intValue();\r
+                       if (mtFaces.size() != facesAmount) {\r
+                               throw new BlenderFileException("The amount of faces uv coordinates is not equal to faces amount!");\r
+                       }\r
+                       uvCoordinates = new ArrayList<Vector2f>();// TODO: calculate the amount of coordinates if possible\r
+               }\r
+\r
+               // normalMap merges normals of faces that will be rendered smooth\r
+               Map<Vector3f, Vector3f> normalMap = new HashMap<Vector3f, Vector3f>(verticesAmount);\r
+\r
+               List<Vector3f> normalList = new ArrayList<Vector3f>();\r
+               List<Vector3f> vertexList = new ArrayList<Vector3f>();\r
+               // indicates if the material with the specified number should have a texture attached\r
+               Map<Integer, Texture> materialNumberToTexture = new HashMap<Integer, Texture>();\r
+               // this map's key is the vertex index from 'vertices 'table and the value are indices from 'vertexList'\r
+               // positions (it simply tells which vertex is referenced where in the result list)\r
+               Map<Integer, List<Integer>> vertexReferenceMap = new HashMap<Integer, List<Integer>>(verticesAmount);\r
+               int vertexColorIndex = 0;\r
+               for (int i = 0; i < mFaces.size(); ++i) {\r
+                       Structure mFace = mFaces.get(i);\r
+                       boolean smooth = (((Number) mFace.getFieldValue("flag")).byteValue() & 0x01) != 0x00;\r
+                       DynamicArray<Number> uvs = null;\r
+                       boolean materialWithoutTextures = false;\r
+                       Pointer pImage = null;\r
+                       if (mtFaces != null) {\r
+                               Structure mtFace = mtFaces.get(i);\r
+                               pImage = (Pointer) mtFace.getFieldValue("tpage");\r
+                               materialWithoutTextures = pImage.isNull();\r
+                               // uvs always must be added wheater we have texture or not\r
+                               uvs = (DynamicArray<Number>) mtFace.getFieldValue("uv");\r
+                               uvCoordinates.add(new Vector2f(uvs.get(0, 0).floatValue(), uvs.get(0, 1).floatValue()));\r
+                               uvCoordinates.add(new Vector2f(uvs.get(1, 0).floatValue(), uvs.get(1, 1).floatValue()));\r
+                               uvCoordinates.add(new Vector2f(uvs.get(2, 0).floatValue(), uvs.get(2, 1).floatValue()));\r
+                       }\r
+                       int matNr = ((Number) mFace.getFieldValue("mat_nr")).intValue();\r
+                       Integer materialNumber = Integer.valueOf(materialWithoutTextures ? -1 * matNr - 1 : matNr);\r
+                       List<Integer> indexList = meshesMap.get(materialNumber);\r
+                       if (indexList == null) {\r
+                               indexList = new ArrayList<Integer>();\r
+                               meshesMap.put(materialNumber, indexList);\r
+                       }\r
+                       \r
+                       // attaching image to texture (face can have UV's and image whlie its material may have no texture attached)\r
+                       if (pImage != null && !pImage.isNull() && !materialNumberToTexture.containsKey(materialNumber)) {\r
+                               Texture texture = textureHelper.getTextureFromImage(pImage.fetchData(dataRepository.getInputStream()).get(0),\r
+                                               dataRepository);\r
+                               if (texture != null) {\r
+                                       materialNumberToTexture.put(materialNumber, texture);\r
+                               }\r
+                       }\r
+\r
+                       int v1 = ((Number) mFace.getFieldValue("v1")).intValue();\r
+                       int v2 = ((Number) mFace.getFieldValue("v2")).intValue();\r
+                       int v3 = ((Number) mFace.getFieldValue("v3")).intValue();\r
+                       int v4 = ((Number) mFace.getFieldValue("v4")).intValue();\r
+\r
+                       Vector3f n = FastMath.computeNormal(vertices[v1], vertices[v2], vertices[v3]);\r
+                       this.addNormal(n, normalMap, smooth, vertices[v1], vertices[v2], vertices[v3]);\r
+                       normalList.add(normalMap.get(vertices[v1]));\r
+                       normalList.add(normalMap.get(vertices[v2]));\r
+                       normalList.add(normalMap.get(vertices[v3]));\r
+\r
+                       this.appendVertexReference(v1, vertexList.size(), vertexReferenceMap);\r
+                       indexList.add(vertexList.size());\r
+                       vertexList.add(vertices[v1]);\r
+\r
+                       this.appendVertexReference(v2, vertexList.size(), vertexReferenceMap);\r
+                       indexList.add(vertexList.size());\r
+                       vertexList.add(vertices[v2]);\r
+\r
+                       this.appendVertexReference(v3, vertexList.size(), vertexReferenceMap);\r
+                       indexList.add(vertexList.size());\r
+                       vertexList.add(vertices[v3]);\r
+\r
+                       if (v4 > 0) {\r
+                               if (uvs != null) {\r
+                                       uvCoordinates.add(new Vector2f(uvs.get(0, 0).floatValue(), uvs.get(0, 1).floatValue()));\r
+                                       uvCoordinates.add(new Vector2f(uvs.get(2, 0).floatValue(), uvs.get(2, 1).floatValue()));\r
+                                       uvCoordinates.add(new Vector2f(uvs.get(3, 0).floatValue(), uvs.get(3, 1).floatValue()));\r
+                               }\r
+                               this.appendVertexReference(v1, vertexList.size(), vertexReferenceMap);\r
+                               indexList.add(vertexList.size());\r
+                               vertexList.add(vertices[v1]);\r
+\r
+                               this.appendVertexReference(v3, vertexList.size(), vertexReferenceMap);\r
+                               indexList.add(vertexList.size());\r
+                               vertexList.add(vertices[v3]);\r
+\r
+                               this.appendVertexReference(v4, vertexList.size(), vertexReferenceMap);\r
+                               indexList.add(vertexList.size());\r
+                               vertexList.add(vertices[v4]);\r
+\r
+                               this.addNormal(n, normalMap, smooth, vertices[v4]);\r
+                               normalList.add(normalMap.get(vertices[v1]));\r
+                               normalList.add(normalMap.get(vertices[v3]));\r
+                               normalList.add(normalMap.get(vertices[v4]));\r
+\r
+                               if (verticesColors != null) {\r
+                                       verticesColors.add(vertexColorIndex + 3, verticesColors.get(vertexColorIndex));\r
+                                       verticesColors.add(vertexColorIndex + 4, verticesColors.get(vertexColorIndex + 2));\r
+                               }\r
+                               vertexColorIndex += 6;\r
+                       } else {\r
+                               if (verticesColors != null) {\r
+                                       verticesColors.remove(vertexColorIndex + 3);\r
+                                       vertexColorIndex += 3;\r
+                               }\r
+                       }\r
+               }\r
+               Vector3f[] normals = normalList.toArray(new Vector3f[normalList.size()]);\r
+\r
+               // reading vertices groups (from the parent)\r
+               Structure parent = dataRepository.peekParent();\r
+               Structure defbase = (Structure) parent.getFieldValue("defbase");\r
+               List<Structure> defs = defbase.evaluateListBase(dataRepository);\r
+               String[] verticesGroups = new String[defs.size()];\r
+               int defIndex = 0;\r
+               for (Structure def : defs) {\r
+                       verticesGroups[defIndex++] = def.getFieldValue("name").toString();\r
+               }\r
+\r
+               // vertices bone weights and indices\r
+               ArmatureHelper armatureHelper = dataRepository.getHelper(ArmatureHelper.class);\r
+               Structure defBase = (Structure) parent.getFieldValue("defbase");\r
+               Map<Integer, Integer> groupToBoneIndexMap = armatureHelper.getGroupToBoneIndexMap(defBase, dataRepository);\r
+\r
+               VertexBuffer verticesWeights = null, verticesWeightsIndices = null;\r
+               int[] bonesGroups = new int[] { 0 };\r
+               VertexBuffer[] boneWeightsAndIndex = this.getBoneWeightAndIndexBuffer(structure, vertexList.size(), bonesGroups,\r
+                               vertexReferenceMap, groupToBoneIndexMap, dataRepository);\r
+               verticesWeights = boneWeightsAndIndex[0];\r
+               verticesWeightsIndices = boneWeightsAndIndex[1];\r
+\r
+               // reading materials\r
+               MaterialHelper materialHelper = dataRepository.getHelper(MaterialHelper.class);\r
+               Material[] materials = null;\r
+               Material[] nonTexturedMaterials = null;\r
+               if ((dataRepository.getBlenderKey().getFeaturesToLoad() & FeaturesToLoad.MATERIALS) != 0) {\r
+                       materials = materialHelper.getMaterials(structure, dataRepository);\r
+                       nonTexturedMaterials = materials == null ? null : new Material[materials.length];// fill it when needed\r
+               }\r
+\r
+               // creating the result meshes\r
+               geometries = new ArrayList<Geometry>(meshesMap.size());\r
+\r
+               VertexBuffer verticesBuffer = new VertexBuffer(Type.Position);\r
+               verticesBuffer.setupData(Usage.Stream, 3, Format.Float,\r
+                               BufferUtils.createFloatBuffer(vertexList.toArray(new Vector3f[vertexList.size()])));\r
+\r
+               // initial vertex position (used with animation)\r
+               VertexBuffer verticesBind = new VertexBuffer(Type.BindPosePosition);\r
+               verticesBind.setupData(Usage.CpuOnly, 3, Format.Float, BufferUtils.clone(verticesBuffer.getData()));\r
+\r
+               VertexBuffer normalsBuffer = new VertexBuffer(Type.Normal);\r
+               normalsBuffer.setupData(Usage.Stream, 3, Format.Float, BufferUtils.createFloatBuffer(normals));\r
+\r
+               // initial normals position (used with animation)\r
+               VertexBuffer normalsBind = new VertexBuffer(Type.BindPoseNormal);\r
+               normalsBind.setupData(Usage.CpuOnly, 3, Format.Float, BufferUtils.clone(normalsBuffer.getData()));\r
+\r
+               VertexBuffer uvCoordsBuffer = null;\r
+               if (uvCoordinates != null) {\r
+                       uvCoordsBuffer = new VertexBuffer(Type.TexCoord);\r
+                       uvCoordsBuffer.setupData(Usage.Static, 2, Format.Float,\r
+                                       BufferUtils.createFloatBuffer(uvCoordinates.toArray(new Vector2f[uvCoordinates.size()])));\r
+               }\r
+\r
+               // generating meshes\r
+               FloatBuffer verticesColorsBuffer = this.createFloatBuffer(verticesColors);\r
+               for (Entry<Integer, List<Integer>> meshEntry : meshesMap.entrySet()) {\r
+                       Mesh mesh = new Mesh();\r
+\r
+                       // creating vertices indices for this mesh\r
+                       List<Integer> indexList = meshEntry.getValue();\r
+                       short[] indices = new short[indexList.size()];//TODO: check if the model doesn't have more than 32767 vertices\r
+                       for (int i = 0; i < indexList.size(); ++i) {//if yes then mesh.getVertices method must be changed to accept other than ShortBuffer\r
+                               indices[i] = indexList.get(i).shortValue();\r
+                       }\r
+\r
+                       // setting vertices\r
+                       mesh.setBuffer(Type.Index, 1, BufferUtils.createShortBuffer(indices));\r
+                       mesh.setBuffer(verticesBuffer);\r
+                       mesh.setBuffer(verticesBind);\r
+\r
+                       // setting vertices colors\r
+                       if (verticesColorsBuffer != null) {\r
+                               mesh.setBuffer(Type.Color, 4, verticesColorsBuffer);\r
+                       }\r
+\r
+                       // setting weights for bones\r
+                       if (verticesWeights != null) {\r
+                               mesh.setMaxNumWeights(bonesGroups[0]);\r
+                               mesh.setBuffer(verticesWeights);\r
+                               mesh.setBuffer(verticesWeightsIndices);\r
+                       }\r
+\r
+                       // setting faces' normals\r
+                       mesh.setBuffer(normalsBuffer);\r
+                       mesh.setBuffer(normalsBind);\r
+\r
+                       // setting uvCoords\r
+                       if (uvCoordsBuffer != null) {\r
+                               mesh.setBuffer(uvCoordsBuffer);\r
+                       }\r
+\r
+                       // creating the result\r
+                       Geometry geometry = new Geometry(name + (geometries.size() + 1), mesh);\r
+                       if (materials != null) {\r
+                               int materialNumber = meshEntry.getKey().intValue();\r
+                               Material material;\r
+                               if (materialNumber >= 0) {\r
+                                       material = materials[materialNumber];\r
+                                       if (materialNumberToTexture.containsKey(Integer.valueOf(materialNumber))) {\r
+                                               if (material.getMaterialDef().getAssetName().contains("Lighting")) {\r
+                                                       if (!materialHelper.hasTexture(material, MaterialHelper.TEXTURE_TYPE_DIFFUSE)) {\r
+                                                               material = material.clone();\r
+                                                               material.setTexture(MaterialHelper.TEXTURE_TYPE_DIFFUSE,\r
+                                                                               materialNumberToTexture.get(Integer.valueOf(materialNumber)));\r
+                                                       }\r
+                                               } else {\r
+                                                       if (!materialHelper.hasTexture(material, MaterialHelper.TEXTURE_TYPE_COLOR)) {\r
+                                                               material = material.clone();\r
+                                                               material.setTexture(MaterialHelper.TEXTURE_TYPE_COLOR,\r
+                                                                               materialNumberToTexture.get(Integer.valueOf(materialNumber)));\r
+                                                       }\r
+                                               }\r
+                                       }\r
+                               } else {\r
+                                       materialNumber = -1 * (materialNumber + 1);\r
+                                       if (nonTexturedMaterials[materialNumber] == null) {\r
+                                               nonTexturedMaterials[materialNumber] = materialHelper.getNonTexturedMaterial(materials[materialNumber],\r
+                                                               TextureHelper.TEX_IMAGE);\r
+                                       }\r
+                                       material = nonTexturedMaterials[materialNumber];\r
+                               }\r
+                               geometry.setMaterial(material);\r
+                       } else {\r
+                               geometry.setMaterial(dataRepository.getDefaultMaterial());\r
+                       }\r
+                       geometries.add(geometry);\r
+               }\r
+               dataRepository.addLoadedFeatures(structure.getOldMemoryAddress(), structure.getName(), structure, geometries);\r
+               return geometries;\r
+       }\r
+\r
+       /**\r
+        * This method adds a normal to a normals' map. This map is used to merge normals of a vertor that should be rendered smooth.\r
+        * \r
+        * @param normalToAdd\r
+        *            a normal to be added\r
+        * @param normalMap\r
+        *            merges normals of faces that will be rendered smooth; the key is the vertex and the value - its normal vector\r
+        * @param smooth\r
+        *            the variable that indicates wheather to merge normals (creating the smooth mesh) or not\r
+        * @param vertices\r
+        *            a list of vertices read from the blender file\r
+        */\r
+       protected void addNormal(Vector3f normalToAdd, Map<Vector3f, Vector3f> normalMap, boolean smooth, Vector3f... vertices) {\r
+               for (Vector3f v : vertices) {\r
+                       Vector3f n = normalMap.get(v);\r
+                       if (!smooth || n == null) {\r
+                               normalMap.put(v, normalToAdd.clone());\r
+                       } else {\r
+                               n.addLocal(normalToAdd).normalizeLocal();\r
+                       }\r
+               }\r
+       }\r
+\r
+       /**\r
+        * This method fills the vertex reference map. The vertices are loaded once and referenced many times in the model. This map is created\r
+        * 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\r
+        * - the reference indices list.\r
+        * \r
+        * @param basicVertexIndex\r
+        *            the index of the vertex from its basic table\r
+        * @param resultIndex\r
+        *            the index of the vertex in its result vertex list\r
+        * @param vertexReferenceMap\r
+        *            the reference map\r
+        */\r
+       protected void appendVertexReference(int basicVertexIndex, int resultIndex, Map<Integer, List<Integer>> vertexReferenceMap) {\r
+               List<Integer> referenceList = vertexReferenceMap.get(Integer.valueOf(basicVertexIndex));\r
+               if (referenceList == null) {\r
+                       referenceList = new ArrayList<Integer>();\r
+                       vertexReferenceMap.put(Integer.valueOf(basicVertexIndex), referenceList);\r
+               }\r
+               referenceList.add(Integer.valueOf(resultIndex));\r
+       }\r
+\r
+       /**\r
+        * This method returns the vertices colors. Each vertex is stored in float[4] array.\r
+        * \r
+        * @param meshStructure\r
+        *            the structure containing the mesh data\r
+        * @param dataRepository\r
+        *            the data repository\r
+        * @return a list of vertices colors, each color belongs to a single vertex\r
+        * @throws BlenderFileException\r
+        *             this exception is thrown when the blend file structure is somehow invalid or corrupted\r
+        */\r
+       public List<float[]> getVerticesColors(Structure meshStructure, DataRepository dataRepository) throws BlenderFileException {\r
+               Pointer pMCol = (Pointer) meshStructure.getFieldValue("mcol");\r
+               List<float[]> verticesColors = null;\r
+               List<Structure> mCol = null;\r
+               if (!pMCol.isNull()) {\r
+                       verticesColors = new LinkedList<float[]>();\r
+                       mCol = pMCol.fetchData(dataRepository.getInputStream());\r
+                       for (Structure color : mCol) {\r
+                               float r = ((Number) color.getFieldValue("r")).byteValue() / 256.0f;\r
+                               float g = ((Number) color.getFieldValue("g")).byteValue() / 256.0f;\r
+                               float b = ((Number) color.getFieldValue("b")).byteValue() / 256.0f;\r
+                               float a = ((Number) color.getFieldValue("a")).byteValue() / 256.0f;\r
+                               verticesColors.add(new float[] { b, g, r, a });\r
+                       }\r
+               }\r
+               return verticesColors;\r
+       }\r
+\r
+       /**\r
+        * This method returns the vertices.\r
+        * \r
+        * @param meshStructure\r
+        *            the structure containing the mesh data\r
+        * @param dataRepository\r
+        *            the data repository\r
+        * @return a list of vertices colors, each color belongs to a single vertex\r
+        * @throws BlenderFileException\r
+        *             this exception is thrown when the blend file structure is somehow invalid or corrupted\r
+        */\r
+       @SuppressWarnings("unchecked")\r
+       public Vector3f[] getVertices(Structure meshStructure, DataRepository dataRepository) throws BlenderFileException {\r
+               int verticesAmount = ((Number) meshStructure.getFieldValue("totvert")).intValue();\r
+               Vector3f[] vertices = new Vector3f[verticesAmount];\r
+               Pointer pMVert = (Pointer) meshStructure.getFieldValue("mvert");\r
+               List<Structure> mVerts = pMVert.fetchData(dataRepository.getInputStream());\r
+               for (int i = 0; i < verticesAmount; ++i) {\r
+                       DynamicArray<Number> coordinates = (DynamicArray<Number>) mVerts.get(i).getFieldValue("co");\r
+                       vertices[i] = new Vector3f(coordinates.get(0).floatValue(), coordinates.get(1).floatValue(), coordinates.get(2).floatValue());\r
+               }\r
+               return vertices;\r
+       }\r
+\r
+       /**\r
+        * 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\r
+        * second element is a vertex buffer holding bone indices for vertices (the indices of bones the vertices are assigned to).\r
+        * \r
+        * @param meshStructure\r
+        *            the mesh structure object\r
+        * @param vertexListSize\r
+        *            a number of vertices in the model\r
+        * @param bonesGroups\r
+        *            this is an output parameter, it should be a one-sized array; the maximum amount of weights per vertex (up to\r
+        *            MAXIMUM_WEIGHTS_PER_VERTEX) is stored there\r
+        * @param vertexReferenceMap\r
+        *            this reference map allows to map the original vertices read from blender to vertices that are really in the model; one\r
+        *            vertex may appear several times in the result model\r
+        * @param groupToBoneIndexMap\r
+        *            this object maps the group index (to which a vertices in blender belong) to bone index of the model\r
+        * @param dataRepository\r
+        *            the data repository\r
+        * @return arrays of vertices weights and their bone indices and (as an outpot parameter) the maximum amount of weights for a vertex\r
+        * @throws BlenderFileException\r
+        *             this exception is thrown when the blend file structure is somehow invalid or corrupted\r
+        */\r
+       public VertexBuffer[] getBoneWeightAndIndexBuffer(Structure meshStructure, int vertexListSize, int[] bonesGroups,\r
+                       Map<Integer, List<Integer>> vertexReferenceMap, Map<Integer, Integer> groupToBoneIndexMap, DataRepository dataRepository)\r
+                       throws BlenderFileException {\r
+               Pointer pDvert = (Pointer) meshStructure.getFieldValue("dvert");// dvert = DeformVERTices\r
+               FloatBuffer weightsFloatData = BufferUtils.createFloatBuffer(vertexListSize * MAXIMUM_WEIGHTS_PER_VERTEX);\r
+               ByteBuffer indicesData = BufferUtils.createByteBuffer(vertexListSize * MAXIMUM_WEIGHTS_PER_VERTEX);\r
+               if (!pDvert.isNull()) {// assigning weights and bone indices\r
+                       List<Structure> dverts = pDvert.fetchData(dataRepository.getInputStream());// dverts.size() == verticesAmount (one dvert per\r
+                                                                                                                                                                               // vertex in blender)\r
+                       int vertexIndex = 0;\r
+                       for (Structure dvert : dverts) {\r
+                               int totweight = ((Number) dvert.getFieldValue("totweight")).intValue();// total amount of weights assignet to the vertex\r
+                                                                                                                                                                               // (max. 4 in JME)\r
+                               Pointer pDW = (Pointer) dvert.getFieldValue("dw");\r
+                               List<Integer> vertexIndices = vertexReferenceMap.get(Integer.valueOf(vertexIndex));// we fetch the referenced vertices here\r
+                               if (totweight > 0 && !pDW.isNull()) {// pDW should never be null here, but I check it just in case :)\r
+                                       int weightIndex = 0;\r
+                                       List<Structure> dw = pDW.fetchData(dataRepository.getInputStream());\r
+                                       for (Structure deformWeight : dw) {\r
+                                               Integer boneIndex = groupToBoneIndexMap.get(((Number) deformWeight.getFieldValue("def_nr")).intValue());\r
+                                               if (boneIndex != null) {// null here means that we came accross group that has no bone attached to\r
+                                                       float weight = ((Number) deformWeight.getFieldValue("weight")).floatValue();\r
+                                                       if (weight == 0.0f) {\r
+                                                               weight = 1;\r
+                                                               boneIndex = Integer.valueOf(0);\r
+                                                       }\r
+                                                       // we apply the weight to all referenced vertices\r
+                                                       for (Integer index : vertexIndices) {\r
+                                                               // all indices are always assigned to 0-indexed bone\r
+                                                               // weightsFloatData.put(index * MAXIMUM_WEIGHTS_PER_VERTEX + weightIndex, 1.0f);\r
+                                                               // indicesData.put(index * MAXIMUM_WEIGHTS_PER_VERTEX + weightIndex, (byte)0);\r
+                                                               // if(weight != 0.0f) {\r
+                                                               weightsFloatData.put(index * MAXIMUM_WEIGHTS_PER_VERTEX + weightIndex, weight);\r
+                                                               indicesData.put(index * MAXIMUM_WEIGHTS_PER_VERTEX + weightIndex, boneIndex.byteValue());\r
+                                                               // }\r
+                                                       }\r
+                                               }\r
+                                               ++weightIndex;\r
+                                       }\r
+                               } else {\r
+                                       for (Integer index : vertexIndices) {\r
+                                               weightsFloatData.put(index * MAXIMUM_WEIGHTS_PER_VERTEX, 1.0f);\r
+                                               indicesData.put(index * MAXIMUM_WEIGHTS_PER_VERTEX, (byte) 0);\r
+                                       }\r
+                               }\r
+                               ++vertexIndex;\r
+                       }\r
+               } else {\r
+                       // always bind all vertices to 0-indexed bone\r
+                       // this bone makes the model look normally if vertices have no bone assigned\r
+                       // and it is used in object animation, so if we come accross object animation\r
+                       // we can use the 0-indexed bone for this\r
+                       for (List<Integer> vertexIndexList : vertexReferenceMap.values()) {\r
+                               // we apply the weight to all referenced vertices\r
+                               for (Integer index : vertexIndexList) {\r
+                                       weightsFloatData.put(index * MAXIMUM_WEIGHTS_PER_VERTEX, 1.0f);\r
+                                       indicesData.put(index * MAXIMUM_WEIGHTS_PER_VERTEX, (byte) 0);\r
+                               }\r
+                       }\r
+               }\r
+\r
+               bonesGroups[0] = this.endBoneAssigns(vertexListSize, weightsFloatData);\r
+               VertexBuffer verticesWeights = new VertexBuffer(Type.BoneWeight);\r
+               verticesWeights.setupData(Usage.CpuOnly, bonesGroups[0], Format.Float, weightsFloatData);\r
+\r
+               VertexBuffer verticesWeightsIndices = new VertexBuffer(Type.BoneIndex);\r
+               verticesWeightsIndices.setupData(Usage.CpuOnly, bonesGroups[0], Format.UnsignedByte, indicesData);\r
+               return new VertexBuffer[] { verticesWeights, verticesWeightsIndices };\r
+       }\r
+\r
+       /**\r
+        * Normalizes weights if needed and finds largest amount of weights used for all vertices in the buffer.\r
+        */\r
+       protected int endBoneAssigns(int vertCount, FloatBuffer weightsFloatData) {\r
+               int maxWeightsPerVert = 0;\r
+               weightsFloatData.rewind();\r
+               for (int v = 0; v < vertCount; ++v) {\r
+                       float w0 = weightsFloatData.get(), w1 = weightsFloatData.get(), w2 = weightsFloatData.get(), w3 = weightsFloatData.get();\r
+\r
+                       if (w3 != 0) {\r
+                               maxWeightsPerVert = Math.max(maxWeightsPerVert, 4);\r
+                       } else if (w2 != 0) {\r
+                               maxWeightsPerVert = Math.max(maxWeightsPerVert, 3);\r
+                       } else if (w1 != 0) {\r
+                               maxWeightsPerVert = Math.max(maxWeightsPerVert, 2);\r
+                       } else if (w0 != 0) {\r
+                               maxWeightsPerVert = Math.max(maxWeightsPerVert, 1);\r
+                       }\r
+\r
+                       float sum = w0 + w1 + w2 + w3;\r
+                       if (sum != 1f && sum != 0.0f) {\r
+                               weightsFloatData.position(weightsFloatData.position() - 4);\r
+                               // compute new vals based on sum\r
+                               float sumToB = 1f / sum;\r
+                               weightsFloatData.put(w0 * sumToB);\r
+                               weightsFloatData.put(w1 * sumToB);\r
+                               weightsFloatData.put(w2 * sumToB);\r
+                               weightsFloatData.put(w3 * sumToB);\r
+                       }\r
+               }\r
+               weightsFloatData.rewind();\r
+\r
+               // mesh.setMaxNumWeights(maxWeightsPerVert);\r
+               return maxWeightsPerVert;\r
+       }\r
 }\r
index aec562c..3331e33 100644 (file)
@@ -217,7 +217,7 @@ public class TextureHelper extends AbstractBlenderHelper {
                                throw new BlenderFileException("Unknown texture type: " + type + " for texture: " + tex.getName());\r
                }\r
                if (result != null) {\r
-                       result.setName(String.valueOf(type));\r
+                       result.setName(tex.getName());\r
                        result.setWrap(WrapMode.Repeat);\r
                }\r
                return result;\r
@@ -1579,7 +1579,6 @@ public class TextureHelper extends AbstractBlenderHelper {
                                }\r
                        }\r
                        if (result != null) {\r
-                               result.setName(String.valueOf(8));// 8 = TEX_IMAGE\r
                                result.setWrap(Texture.WrapMode.Repeat);\r
                                dataRepository.addLoadedFeatures(image.getOldMemoryAddress(), image.getName(), image, result);\r
                        }\r