• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2009-2012 jMonkeyEngine
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are
7  * met:
8  *
9  * * Redistributions of source code must retain the above copyright
10  *   notice, this list of conditions and the following disclaimer.
11  *
12  * * Redistributions in binary form must reproduce the above copyright
13  *   notice, this list of conditions and the following disclaimer in the
14  *   documentation and/or other materials provided with the distribution.
15  *
16  * * Neither the name of 'jMonkeyEngine' nor the names of its contributors
17  *   may be used to endorse or promote products derived from this software
18  *   without specific prior written permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
22  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
23  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
24  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
25  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
26  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
27  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
28  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
29  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
30  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31  */
32 package com.jme3.scene.plugins.blender.materials;
33 
34 import com.jme3.asset.BlenderKey.FeaturesToLoad;
35 import com.jme3.material.MatParam;
36 import com.jme3.material.MatParamTexture;
37 import com.jme3.material.Material;
38 import com.jme3.material.RenderState.BlendMode;
39 import com.jme3.material.RenderState.FaceCullMode;
40 import com.jme3.math.ColorRGBA;
41 import com.jme3.math.FastMath;
42 import com.jme3.scene.plugins.blender.AbstractBlenderHelper;
43 import com.jme3.scene.plugins.blender.BlenderContext;
44 import com.jme3.scene.plugins.blender.BlenderContext.LoadedFeatureDataType;
45 import com.jme3.scene.plugins.blender.exceptions.BlenderFileException;
46 import com.jme3.scene.plugins.blender.file.Pointer;
47 import com.jme3.scene.plugins.blender.file.Structure;
48 import com.jme3.shader.VarType;
49 import com.jme3.texture.Image;
50 import com.jme3.texture.Image.Format;
51 import com.jme3.texture.Texture;
52 import com.jme3.texture.Texture.Type;
53 import com.jme3.util.BufferUtils;
54 import java.nio.ByteBuffer;
55 import java.util.HashMap;
56 import java.util.List;
57 import java.util.Map;
58 import java.util.Map.Entry;
59 import java.util.logging.Level;
60 import java.util.logging.Logger;
61 
62 public class MaterialHelper extends AbstractBlenderHelper {
63 	private static final Logger					LOGGER					= Logger.getLogger(MaterialHelper.class.getName());
64 	protected static final float				DEFAULT_SHININESS		= 20.0f;
65 
66 	public static final String					TEXTURE_TYPE_3D			= "Texture";
67 	public static final String					TEXTURE_TYPE_COLOR		= "ColorMap";
68 	public static final String					TEXTURE_TYPE_DIFFUSE	= "DiffuseMap";
69 	public static final String					TEXTURE_TYPE_NORMAL		= "NormalMap";
70 	public static final String					TEXTURE_TYPE_SPECULAR	= "SpecularMap";
71 	public static final String					TEXTURE_TYPE_GLOW		= "GlowMap";
72 	public static final String					TEXTURE_TYPE_ALPHA		= "AlphaMap";
73 
74 	public static final Integer					ALPHA_MASK_NONE			= Integer.valueOf(0);
75 	public static final Integer					ALPHA_MASK_CIRCLE		= Integer.valueOf(1);
76 	public static final Integer					ALPHA_MASK_CONE			= Integer.valueOf(2);
77 	public static final Integer					ALPHA_MASK_HYPERBOLE	= Integer.valueOf(3);
78 	protected final Map<Integer, IAlphaMask>	alphaMasks				= new HashMap<Integer, IAlphaMask>();
79 
80 	/**
81 	 * The type of the material's diffuse shader.
82 	 */
83 	public static enum DiffuseShader {
84 		LAMBERT, ORENNAYAR, TOON, MINNAERT, FRESNEL
85 	}
86 
87 	/**
88 	 * The type of the material's specular shader.
89 	 */
90 	public static enum SpecularShader {
91 		COOKTORRENCE, PHONG, BLINN, TOON, WARDISO
92 	}
93 
94 	/** Face cull mode. Should be excplicitly set before this helper is used. */
95 	protected FaceCullMode	faceCullMode;
96 
97 	/**
98 	 * This constructor parses the given blender version and stores the result. Some functionalities may differ in different blender
99 	 * versions.
100 	 *
101 	 * @param blenderVersion
102 	 *        the version read from the blend file
103 	 * @param fixUpAxis
104      *        a variable that indicates if the Y asxis is the UP axis or not
105 	 */
MaterialHelper(String blenderVersion, boolean fixUpAxis)106 	public MaterialHelper(String blenderVersion, boolean fixUpAxis) {
107 		super(blenderVersion, false);
108 		// setting alpha masks
109 		alphaMasks.put(ALPHA_MASK_NONE, new IAlphaMask() {
110 			@Override
111 			public void setImageSize(int width, int height) {}
112 
113 			@Override
114 			public byte getAlpha(float x, float y) {
115 				return (byte) 255;
116 			}
117 		});
118 		alphaMasks.put(ALPHA_MASK_CIRCLE, new IAlphaMask() {
119 			private float	r;
120 			private float[]	center;
121 
122 			@Override
123 			public void setImageSize(int width, int height) {
124 				r = Math.min(width, height) * 0.5f;
125 				center = new float[] { width * 0.5f, height * 0.5f };
126 			}
127 
128 			@Override
129 			public byte getAlpha(float x, float y) {
130 				float d = FastMath.abs(FastMath.sqrt((x - center[0]) * (x - center[0]) + (y - center[1]) * (y - center[1])));
131 				return (byte) (d >= r ? 0 : 255);
132 			}
133 		});
134 		alphaMasks.put(ALPHA_MASK_CONE, new IAlphaMask() {
135 			private float	r;
136 			private float[]	center;
137 
138 			@Override
139 			public void setImageSize(int width, int height) {
140 				r = Math.min(width, height) * 0.5f;
141 				center = new float[] { width * 0.5f, height * 0.5f };
142 			}
143 
144 			@Override
145 			public byte getAlpha(float x, float y) {
146 				float d = FastMath.abs(FastMath.sqrt((x - center[0]) * (x - center[0]) + (y - center[1]) * (y - center[1])));
147 				return (byte) (d >= r ? 0 : -255.0f * d / r + 255.0f);
148 			}
149 		});
150 		alphaMasks.put(ALPHA_MASK_HYPERBOLE, new IAlphaMask() {
151 			private float	r;
152 			private float[]	center;
153 
154 			@Override
155 			public void setImageSize(int width, int height) {
156 				r = Math.min(width, height) * 0.5f;
157 				center = new float[] { width * 0.5f, height * 0.5f };
158 			}
159 
160 			@Override
161 			public byte getAlpha(float x, float y) {
162 				float d = FastMath.abs(FastMath.sqrt((x - center[0]) * (x - center[0]) + (y - center[1]) * (y - center[1]))) / r;
163 				return d >= 1.0f ? 0 : (byte) ((-FastMath.sqrt((2.0f - d) * d) + 1.0f) * 255.0f);
164 			}
165 		});
166 	}
167 
168 	/**
169 	 * This method sets the face cull mode to be used with every loaded material.
170 	 *
171 	 * @param faceCullMode
172 	 *        the face cull mode
173 	 */
setFaceCullMode(FaceCullMode faceCullMode)174 	public void setFaceCullMode(FaceCullMode faceCullMode) {
175 		this.faceCullMode = faceCullMode;
176 	}
177 
178 	/**
179 	 * This method converts the material structure to jme Material.
180 	 * @param structure
181 	 *        structure with material data
182 	 * @param blenderContext
183 	 *        the blender context
184 	 * @return jme material
185 	 * @throws BlenderFileException
186 	 *         an exception is throw when problems with blend file occur
187 	 */
toMaterial(Structure structure, BlenderContext blenderContext)188 	public Material toMaterial(Structure structure, BlenderContext blenderContext) throws BlenderFileException {
189 		LOGGER.log(Level.INFO, "Loading material.");
190 		if (structure == null) {
191 			return blenderContext.getDefaultMaterial();
192 		}
193 		Material result = (Material) blenderContext.getLoadedFeature(structure.getOldMemoryAddress(), LoadedFeatureDataType.LOADED_FEATURE);
194 		if (result != null) {
195 			return result;
196 		}
197 
198 		MaterialContext materialContext = new MaterialContext(structure, blenderContext);
199 		LOGGER.log(Level.INFO, "Material's name: {0}", materialContext.name);
200 
201 		if(materialContext.textures.size() > 1) {
202 			LOGGER.log(Level.WARNING, "Attetion! Many textures found for material: {0}. Only the first of each supported mapping types will be used!", materialContext.name);
203 		}
204 
205 		// texture
206 		Type colorTextureType = null;
207 		Map<String, Texture> texturesMap = new HashMap<String, Texture>();
208 		for(Entry<Number, Texture> textureEntry : materialContext.loadedTextures.entrySet()) {
209 			int mapto = textureEntry.getKey().intValue();
210 			Texture texture = textureEntry.getValue();
211 			if ((mapto & MaterialContext.MTEX_COL) != 0) {
212 				colorTextureType = texture.getType();
213 				if (materialContext.shadeless) {
214 					texturesMap.put(colorTextureType==Type.ThreeDimensional ? TEXTURE_TYPE_3D : TEXTURE_TYPE_COLOR, texture);
215 				} else {
216 					texturesMap.put(colorTextureType==Type.ThreeDimensional ? TEXTURE_TYPE_3D : TEXTURE_TYPE_DIFFUSE, texture);
217 				}
218 			}
219 			if(texture.getType()==Type.TwoDimensional) {//so far only 2D textures can be mapped in other way than color
220 				if ((mapto & MaterialContext.MTEX_NOR) != 0 && !materialContext.shadeless) {
221 					//Structure mTex = materialContext.getMTex(texture);
222 					//Texture normalMapTexture = textureHelper.convertToNormalMapTexture(texture, ((Number) mTex.getFieldValue("norfac")).floatValue());
223 					//texturesMap.put(TEXTURE_TYPE_NORMAL, normalMapTexture);
224                                         texturesMap.put(TEXTURE_TYPE_NORMAL, texture);
225 				}
226 				if ((mapto & MaterialContext.MTEX_EMIT) != 0) {
227 					texturesMap.put(TEXTURE_TYPE_GLOW, texture);
228 				}
229 				if ((mapto & MaterialContext.MTEX_SPEC) != 0 && !materialContext.shadeless) {
230 					texturesMap.put(TEXTURE_TYPE_SPECULAR, texture);
231 				}
232 				if ((mapto & MaterialContext.MTEX_ALPHA) != 0 && !materialContext.shadeless) {
233 					texturesMap.put(TEXTURE_TYPE_ALPHA, texture);
234 				}
235 			}
236 		}
237 
238 		//creating the material
239 		if(colorTextureType==Type.ThreeDimensional) {
240 			result = new Material(blenderContext.getAssetManager(), "Common/MatDefs/Texture3D/tex3D.j3md");
241 		} else {
242 			if (materialContext.shadeless) {
243 				result = new Material(blenderContext.getAssetManager(), "Common/MatDefs/Misc/Unshaded.j3md");
244 
245                 if (!materialContext.transparent) {
246                     materialContext.diffuseColor.a = 1;
247                 }
248 
249                 result.setColor("Color", materialContext.diffuseColor);
250 			} else {
251 				result = new Material(blenderContext.getAssetManager(), "Common/MatDefs/Light/Lighting.j3md");
252 				result.setBoolean("UseMaterialColors", Boolean.TRUE);
253 
254 				// setting the colors
255 				result.setBoolean("Minnaert", materialContext.diffuseShader == DiffuseShader.MINNAERT);
256 				if (!materialContext.transparent) {
257 					materialContext.diffuseColor.a = 1;
258 				}
259 				result.setColor("Diffuse", materialContext.diffuseColor);
260 
261 				result.setBoolean("WardIso", materialContext.specularShader == SpecularShader.WARDISO);
262 				result.setColor("Specular", materialContext.specularColor);
263 
264 				result.setColor("Ambient", materialContext.ambientColor);
265 				result.setFloat("Shininess", materialContext.shininess);
266 			}
267 
268 			if (materialContext.vertexColor) {
269 				result.setBoolean(materialContext.shadeless ? "VertexColor" : "UseVertexColor", true);
270 			}
271 		}
272 
273 		//applying textures
274 		for(Entry<String, Texture> textureEntry : texturesMap.entrySet()) {
275 			result.setTexture(textureEntry.getKey(), textureEntry.getValue());
276 		}
277 
278 		//applying other data
279 		result.getAdditionalRenderState().setFaceCullMode(faceCullMode);
280 		if (materialContext.transparent) {
281 			result.setTransparent(true);
282 			result.getAdditionalRenderState().setBlendMode(BlendMode.Alpha);
283 		}
284 
285 		result.setName(materialContext.getName());
286 		blenderContext.setMaterialContext(result, materialContext);
287 		blenderContext.addLoadedFeatures(structure.getOldMemoryAddress(), structure.getName(), structure, result);
288 		return result;
289 	}
290 
291 	/**
292 	 * This method returns a material similar to the one given but without textures. If the material has no textures it is not cloned but
293 	 * returned itself.
294 	 *
295 	 * @param material
296 	 *        a material to be cloned without textures
297 	 * @param imageType
298 	 *        type of image defined by blender; the constants are defined in TextureHelper
299 	 * @return material without textures of a specified type
300 	 */
getNonTexturedMaterial(Material material, int imageType)301 	public Material getNonTexturedMaterial(Material material, int imageType) {
302 		String[] textureParamNames = new String[] { TEXTURE_TYPE_DIFFUSE, TEXTURE_TYPE_NORMAL, TEXTURE_TYPE_GLOW, TEXTURE_TYPE_SPECULAR, TEXTURE_TYPE_ALPHA };
303 		Map<String, Texture> textures = new HashMap<String, Texture>(textureParamNames.length);
304 		for (String textureParamName : textureParamNames) {
305 			MatParamTexture matParamTexture = material.getTextureParam(textureParamName);
306 			if (matParamTexture != null) {
307 				textures.put(textureParamName, matParamTexture.getTextureValue());
308 			}
309 		}
310 		if (textures.isEmpty()) {
311 			return material;
312 		} else {
313 			// clear all textures first so that wo de not waste resources cloning them
314 			for (Entry<String, Texture> textureParamName : textures.entrySet()) {
315 				String name = textureParamName.getValue().getName();
316 				try {
317 					int type = Integer.parseInt(name);
318 					if (type == imageType) {
319 						material.clearParam(textureParamName.getKey());
320 					}
321 				} catch (NumberFormatException e) {
322 					LOGGER.log(Level.WARNING, "The name of the texture does not contain the texture type value! {0} will not be removed!", name);
323 				}
324 			}
325 			Material result = material.clone();
326 			// put the textures back in place
327 			for (Entry<String, Texture> textureEntry : textures.entrySet()) {
328 				material.setTexture(textureEntry.getKey(), textureEntry.getValue());
329 			}
330 			return result;
331 		}
332 	}
333 
334 	/**
335 	 * This method converts the given material into particles-usable material.
336 	 * The texture and glow color are being copied.
337 	 * The method assumes it receives the Lighting type of material.
338 	 * @param material
339 	 *        the source material
340 	 * @param blenderContext
341 	 *        the blender context
342 	 * @return material converted into particles-usable material
343 	 */
getParticlesMaterial(Material material, Integer alphaMaskIndex, BlenderContext blenderContext)344 	public Material getParticlesMaterial(Material material, Integer alphaMaskIndex, BlenderContext blenderContext) {
345 		Material result = new Material(blenderContext.getAssetManager(), "Common/MatDefs/Misc/Particle.j3md");
346 
347 		// copying texture
348 		MatParam diffuseMap = material.getParam("DiffuseMap");
349 		if (diffuseMap != null) {
350 			Texture texture = ((Texture) diffuseMap.getValue()).clone();
351 
352 			// applying alpha mask to the texture
353 			Image image = texture.getImage();
354 			ByteBuffer sourceBB = image.getData(0);
355 			sourceBB.rewind();
356 			int w = image.getWidth();
357 			int h = image.getHeight();
358 			ByteBuffer bb = BufferUtils.createByteBuffer(w * h * 4);
359 			IAlphaMask iAlphaMask = alphaMasks.get(alphaMaskIndex);
360 			iAlphaMask.setImageSize(w, h);
361 
362 			for (int x = 0; x < w; ++x) {
363 				for (int y = 0; y < h; ++y) {
364 					bb.put(sourceBB.get());
365 					bb.put(sourceBB.get());
366 					bb.put(sourceBB.get());
367 					bb.put(iAlphaMask.getAlpha(x, y));
368 				}
369 			}
370 
371 			image = new Image(Format.RGBA8, w, h, bb);
372 			texture.setImage(image);
373 
374 			result.setTextureParam("Texture", VarType.Texture2D, texture);
375 		}
376 
377 		// copying glow color
378 		MatParam glowColor = material.getParam("GlowColor");
379 		if (glowColor != null) {
380 			ColorRGBA color = (ColorRGBA) glowColor.getValue();
381 			result.setParam("GlowColor", VarType.Vector3, color);
382 		}
383 		return result;
384 	}
385 
386 	/**
387 	 * This method indicates if the material has any kind of texture.
388 	 *
389 	 * @param material
390 	 *        the material
391 	 * @return <b>true</b> if the texture exists in the material and <B>false</b> otherwise
392 	 */
hasTexture(Material material)393 	public boolean hasTexture(Material material) {
394 		if (material != null) {
395 			if (material.getTextureParam(TEXTURE_TYPE_3D) != null) {
396 				return true;
397 			}
398 			if (material.getTextureParam(TEXTURE_TYPE_ALPHA) != null) {
399 				return true;
400 			}
401 			if (material.getTextureParam(TEXTURE_TYPE_COLOR) != null) {
402 				return true;
403 			}
404 			if (material.getTextureParam(TEXTURE_TYPE_DIFFUSE) != null) {
405 				return true;
406 			}
407 			if (material.getTextureParam(TEXTURE_TYPE_GLOW) != null) {
408 				return true;
409 			}
410 			if (material.getTextureParam(TEXTURE_TYPE_NORMAL) != null) {
411 				return true;
412 			}
413 			if (material.getTextureParam(TEXTURE_TYPE_SPECULAR) != null) {
414 				return true;
415 			}
416 		}
417 		return false;
418 	}
419 
420 	/**
421 	 * This method indicates if the material has a texture of a specified type.
422 	 *
423 	 * @param material
424 	 *        the material
425 	 * @param textureType
426 	 *        the type of the texture
427 	 * @return <b>true</b> if the texture exists in the material and <B>false</b> otherwise
428 	 */
hasTexture(Material material, String textureType)429 	public boolean hasTexture(Material material, String textureType) {
430 		if (material != null) {
431 			return material.getTextureParam(textureType) != null;
432 		}
433 		return false;
434 	}
435 
436 	/**
437 	 * This method returns the table of materials connected to the specified structure. The given structure can be of any type (ie. mesh or
438 	 * curve) but needs to have 'mat' field/
439 	 *
440 	 * @param structureWithMaterials
441 	 *        the structure containing the mesh data
442 	 * @param blenderContext
443 	 *        the blender context
444 	 * @return a list of vertices colors, each color belongs to a single vertex
445 	 * @throws BlenderFileException
446 	 *         this exception is thrown when the blend file structure is somehow invalid or corrupted
447 	 */
getMaterials(Structure structureWithMaterials, BlenderContext blenderContext)448 	public Material[] getMaterials(Structure structureWithMaterials, BlenderContext blenderContext) throws BlenderFileException {
449 		Pointer ppMaterials = (Pointer) structureWithMaterials.getFieldValue("mat");
450 		Material[] materials = null;
451 		if (ppMaterials.isNotNull()) {
452 			List<Structure> materialStructures = ppMaterials.fetchData(blenderContext.getInputStream());
453 			if (materialStructures != null && materialStructures.size() > 0) {
454 				MaterialHelper materialHelper = blenderContext.getHelper(MaterialHelper.class);
455 				materials = new Material[materialStructures.size()];
456 				int i = 0;
457 				for (Structure s : materialStructures) {
458 					Material material = (Material) blenderContext.getLoadedFeature(s.getOldMemoryAddress(), LoadedFeatureDataType.LOADED_FEATURE);
459 					if (material == null) {
460 						material = materialHelper.toMaterial(s, blenderContext);
461 					}
462 					materials[i++] = material;
463 				}
464 			}
465 		}
466 		return materials;
467 	}
468 
469 	/**
470 	 * This method converts rgb values to hsv values.
471 	 *
472 	 * @param r
473 	 *        red value of the color
474          * @param g
475          *        green value of the color
476          * @param b
477          *        blue value of the color
478 	 * @param hsv
479 	 *        hsv values of a color (this table contains the result of the transformation)
480 	 */
rgbToHsv(float r, float g, float b, float[] hsv)481 	public void rgbToHsv(float r, float g, float b, float[] hsv) {
482 		float cmax = r;
483 		float cmin = r;
484 		cmax = g > cmax ? g : cmax;
485 		cmin = g < cmin ? g : cmin;
486 		cmax = b > cmax ? b : cmax;
487 		cmin = b < cmin ? b : cmin;
488 
489 		hsv[2] = cmax; /* value */
490 		if (cmax != 0.0) {
491 			hsv[1] = (cmax - cmin) / cmax;
492 		} else {
493 			hsv[1] = 0.0f;
494 			hsv[0] = 0.0f;
495 		}
496 		if (hsv[1] == 0.0) {
497 			hsv[0] = -1.0f;
498 		} else {
499 			float cdelta = cmax - cmin;
500 			float rc = (cmax - r) / cdelta;
501 			float gc = (cmax - g) / cdelta;
502 			float bc = (cmax - b) / cdelta;
503 			if (r == cmax) {
504 				hsv[0] = bc - gc;
505 			} else if (g == cmax) {
506 				hsv[0] = 2.0f + rc - bc;
507 			} else {
508 				hsv[0] = 4.0f + gc - rc;
509 			}
510 			hsv[0] *= 60.0f;
511 			if (hsv[0] < 0.0f) {
512 				hsv[0] += 360.0f;
513 			}
514 		}
515 
516 		hsv[0] /= 360.0f;
517 		if (hsv[0] < 0.0f) {
518 			hsv[0] = 0.0f;
519 		}
520 	}
521 
522 	/**
523 	 * This method converts rgb values to hsv values.
524 	 *
525 	 * @param h
526 	 *        hue
527 	 * @param s
528 	 *        saturation
529 	 * @param v
530 	 *        value
531 	 * @param rgb
532 	 *        rgb result vector (should have 3 elements)
533 	 */
534 	public void hsvToRgb(float h, float s, float v, float[] rgb) {
535 		h *= 360.0f;
536 		if (s == 0.0) {
537 			rgb[0] = rgb[1] = rgb[2] = v;
538 		} else {
539 			if (h == 360) {
540 				h = 0;
541 			} else {
542 				h /= 60;
543 			}
544 			int i = (int) Math.floor(h);
545 			float f = h - i;
546 			float p = v * (1.0f - s);
547 			float q = v * (1.0f - s * f);
548 			float t = v * (1.0f - s * (1.0f - f));
549 			switch (i) {
550 				case 0:
551 					rgb[0] = v;
552 					rgb[1] = t;
553 					rgb[2] = p;
554 					break;
555 				case 1:
556 					rgb[0] = q;
557 					rgb[1] = v;
558 					rgb[2] = p;
559 					break;
560 				case 2:
561 					rgb[0] = p;
562 					rgb[1] = v;
563 					rgb[2] = t;
564 					break;
565 				case 3:
566 					rgb[0] = p;
567 					rgb[1] = q;
568 					rgb[2] = v;
569 					break;
570 				case 4:
571 					rgb[0] = t;
572 					rgb[1] = p;
573 					rgb[2] = v;
574 					break;
575 				case 5:
576 					rgb[0] = v;
577 					rgb[1] = p;
578 					rgb[2] = q;
579 					break;
580 			}
581 		}
582 	}
583 
584 	@Override
585 	public boolean shouldBeLoaded(Structure structure, BlenderContext blenderContext) {
586 		return (blenderContext.getBlenderKey().getFeaturesToLoad() & FeaturesToLoad.MATERIALS) != 0;
587 	}
588 }
589