• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2009-2010 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 
33 package com.jme3.scene.plugins.ogre;
34 
35 import com.jme3.asset.*;
36 import com.jme3.material.Material;
37 import com.jme3.material.MaterialList;
38 import com.jme3.material.RenderState;
39 import com.jme3.math.ColorRGBA;
40 import com.jme3.scene.plugins.ogre.matext.MaterialExtensionLoader;
41 import com.jme3.scene.plugins.ogre.matext.MaterialExtensionSet;
42 import com.jme3.scene.plugins.ogre.matext.OgreMaterialKey;
43 import com.jme3.texture.Texture;
44 import com.jme3.texture.Texture.WrapMode;
45 import com.jme3.texture.Texture2D;
46 import com.jme3.util.PlaceholderAssets;
47 import com.jme3.util.blockparser.BlockLanguageParser;
48 import com.jme3.util.blockparser.Statement;
49 import java.io.IOException;
50 import java.io.InputStream;
51 import java.util.Arrays;
52 import java.util.List;
53 import java.util.Scanner;
54 import java.util.logging.Level;
55 import java.util.logging.Logger;
56 
57 public class MaterialLoader implements AssetLoader {
58 
59     private static final Logger logger = Logger.getLogger(MaterialLoader.class.getName());
60 
61     private String folderName;
62     private AssetManager assetManager;
63     private ColorRGBA ambient, diffuse, specular, emissive;
64     private Texture[] textures = new Texture[4];
65     private String texName;
66     private String matName;
67     private float shinines;
68     private boolean vcolor = false;
69     private boolean blend = false;
70     private boolean twoSide = false;
71     private boolean noLight = false;
72     private boolean separateTexCoord = false;
73     private int texUnit = 0;
74 
readColor(String content)75     private ColorRGBA readColor(String content){
76         String[] split = content.split("\\s");
77 
78         ColorRGBA color = new ColorRGBA();
79         color.r = Float.parseFloat(split[0]);
80         color.g = Float.parseFloat(split[1]);
81         color.b = Float.parseFloat(split[2]);
82         if (split.length >= 4){
83             color.a = Float.parseFloat(split[3]);
84         }
85         return color;
86     }
87 
readTextureImage(String content)88     private void readTextureImage(String content){
89         // texture image def
90         String path = null;
91 
92         // find extension
93         int extStart = content.lastIndexOf(".");
94         for (int i = extStart; i < content.length(); i++){
95             char c = content.charAt(i);
96             if (Character.isWhitespace(c)){
97                 // extension ends here
98                 path = content.substring(0, i).trim();
99                 content   = content.substring(i+1).trim();
100                 break;
101             }
102         }
103         if (path == null){
104             path = content.trim();
105             content = "";
106         }
107 
108         Scanner lnScan = new Scanner(content);
109         String mips = null;
110         String type = null;
111         if (lnScan.hasNext()){
112             // more params
113             type = lnScan.next();
114 //            if (!lnScan.hasNext("\n") && lnScan.hasNext()){
115 //                mips = lnScan.next();
116 //                if (lnScan.hasNext()){
117                     // even more params..
118                     // will have to ignore
119 //                }
120 //            }
121         }
122 
123         boolean genMips = true;
124         boolean cubic = false;
125         if (type != null && type.equals("0"))
126             genMips = false;
127 
128         if (type != null && type.equals("cubic")){
129             cubic = true;
130         }
131 
132         TextureKey texKey = new TextureKey(folderName + path, false);
133         texKey.setGenerateMips(genMips);
134         texKey.setAsCube(cubic);
135 
136         try {
137             Texture loadedTexture = assetManager.loadTexture(texKey);
138 
139             textures[texUnit].setImage(loadedTexture.getImage());
140             textures[texUnit].setMinFilter(loadedTexture.getMinFilter());
141             textures[texUnit].setKey(loadedTexture.getKey());
142 
143             // XXX: Is this really neccessary?
144             textures[texUnit].setWrap(WrapMode.Repeat);
145             if (texName != null){
146                 textures[texUnit].setName(texName);
147                 texName = null;
148             }else{
149                 textures[texUnit].setName(texKey.getName());
150             }
151         } catch (AssetNotFoundException ex){
152             logger.log(Level.WARNING, "Cannot locate {0} for material {1}", new Object[]{texKey, matName});
153             textures[texUnit].setImage(PlaceholderAssets.getPlaceholderImage());
154         }
155     }
156 
readTextureUnitStatement(Statement statement)157     private void readTextureUnitStatement(Statement statement){
158         String[] split = statement.getLine().split(" ", 2);
159         String keyword = split[0];
160         if (keyword.equals("texture")){
161             readTextureImage(split[1]);
162         }else if (keyword.equals("tex_address_mode")){
163             String mode = split[1];
164             if (mode.equals("wrap")){
165                 textures[texUnit].setWrap(WrapMode.Repeat);
166             }else if (mode.equals("clamp")){
167                 textures[texUnit].setWrap(WrapMode.Clamp);
168             }else if (mode.equals("mirror")){
169                 textures[texUnit].setWrap(WrapMode.MirroredRepeat);
170             }else if (mode.equals("border")){
171                 textures[texUnit].setWrap(WrapMode.BorderClamp);
172             }
173         }else if (keyword.equals("filtering")){
174             // ignored.. only anisotropy is considered
175         }else if (keyword.equals("tex_coord_set")){
176             int texCoord = Integer.parseInt(split[1]);
177             if (texCoord == 1){
178                 separateTexCoord = true;
179             }
180         }else if (keyword.equals("max_anisotropy")){
181             int amount = Integer.parseInt(split[1]);
182             textures[texUnit].setAnisotropicFilter(amount);
183         }else{
184             logger.log(Level.WARNING, "Unsupported texture_unit directive: {0}", keyword);
185         }
186     }
187 
readTextureUnit(Statement statement)188     private void readTextureUnit(Statement statement){
189         String[] split = statement.getLine().split(" ", 2);
190         // name is optional
191         if (split.length == 2){
192             texName = split[1];
193         }else{
194             texName = null;
195         }
196 
197         textures[texUnit] = new Texture2D();
198         for (Statement texUnitStat : statement.getContents()){
199             readTextureUnitStatement(texUnitStat);
200         }
201         if (textures[texUnit].getImage() != null){
202             texUnit++;
203         }else{
204             // no image was loaded, ignore
205             textures[texUnit] = null;
206         }
207     }
208 
readPassStatement(Statement statement)209     private void readPassStatement(Statement statement){
210         // read until newline
211         String[] split = statement.getLine().split(" ", 2);
212         String keyword = split[0];
213         if (keyword.equals("diffuse")){
214             if (split[1].equals("vertexcolour")){
215                 // use vertex colors
216                 diffuse = ColorRGBA.White;
217                 vcolor = true;
218             }else{
219                 diffuse = readColor(split[1]);
220             }
221         }else if(keyword.equals("ambient")) {
222            if (split[1].equals("vertexcolour")){
223                 // use vertex colors
224                ambient = ColorRGBA.White;
225             }else{
226                ambient = readColor(split[1]);
227             }
228         }else if (keyword.equals("emissive")){
229             emissive = readColor(split[1]);
230         }else if (keyword.equals("specular")){
231             String[] subsplit = split[1].split("\\s");
232             specular = new ColorRGBA();
233             specular.r = Float.parseFloat(subsplit[0]);
234             specular.g = Float.parseFloat(subsplit[1]);
235             specular.b = Float.parseFloat(subsplit[2]);
236             float unknown = Float.parseFloat(subsplit[3]);
237             if (subsplit.length >= 5){
238                 // using 5 float values
239                 specular.a = unknown;
240                 shinines = Float.parseFloat(subsplit[4]);
241             }else{
242                 // using 4 float values
243                 specular.a = 1f;
244                 shinines = unknown;
245             }
246         }else if (keyword.equals("texture_unit")){
247             readTextureUnit(statement);
248         }else if (keyword.equals("scene_blend")){
249             String mode = split[1];
250             if (mode.equals("alpha_blend")){
251                 blend = true;
252             }
253         }else if (keyword.equals("cull_hardware")){
254             String mode = split[1];
255             if (mode.equals("none")){
256                 twoSide = true;
257             }
258         }else if (keyword.equals("cull_software")){
259             // ignore
260         }else if (keyword.equals("lighting")){
261             String isOn = split[1];
262             if (isOn.equals("on")){
263                 noLight = false;
264             }else if (isOn.equals("off")){
265                 noLight = true;
266             }
267         }else{
268             logger.log(Level.WARNING, "Unsupported pass directive: {0}", keyword);
269         }
270     }
271 
readPass(Statement statement)272     private void readPass(Statement statement){
273         String name;
274         String[] split = statement.getLine().split(" ", 2);
275         if (split.length == 1){
276             // no name
277             name = null;
278         }else{
279             name = split[1];
280         }
281 
282         for (Statement passStat : statement.getContents()){
283             readPassStatement(passStat);
284         }
285 
286         texUnit = 0;
287     }
288 
readTechnique(Statement statement)289     private void readTechnique(Statement statement){
290         String[] split = statement.getLine().split(" ", 2);
291         String name;
292         if (split.length == 1){
293             // no name
294             name = null;
295         }else{
296             name = split[1];
297         }
298         for (Statement techStat : statement.getContents()){
299             readPass(techStat);
300         }
301     }
302 
readMaterialStatement(Statement statement)303     private void readMaterialStatement(Statement statement){
304         if (statement.getLine().startsWith("technique")){
305             readTechnique(statement);
306         }else if (statement.getLine().startsWith("receive_shadows")){
307             String isOn = statement.getLine().split("\\s")[1];
308             if (isOn != null && isOn.equals("true")){
309             }
310         }
311     }
312 
313     @SuppressWarnings("empty-statement")
readMaterial(Statement statement)314     private void readMaterial(Statement statement){
315         for (Statement materialStat : statement.getContents()){
316             readMaterialStatement(materialStat);
317         }
318     }
319 
compileMaterial()320     private Material compileMaterial(){
321         Material mat;
322         if (noLight){
323            mat = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md");
324         }else{
325            mat = new Material(assetManager, "Common/MatDefs/Light/Lighting.j3md");
326         }
327         if (blend){
328             RenderState rs = mat.getAdditionalRenderState();
329             rs.setAlphaTest(true);
330             rs.setAlphaFallOff(0.01f);
331             rs.setBlendMode(RenderState.BlendMode.Alpha);
332 
333             if (twoSide){
334                 rs.setFaceCullMode(RenderState.FaceCullMode.Off);
335             }
336 
337 //            rs.setDepthWrite(false);
338             mat.setTransparent(true);
339             if (!noLight){
340                 mat.setBoolean("UseAlpha", true);
341             }
342         }else{
343             if (twoSide){
344                 RenderState rs = mat.getAdditionalRenderState();
345                 rs.setFaceCullMode(RenderState.FaceCullMode.Off);
346             }
347         }
348 
349         if (!noLight){
350             if (shinines > 0f) {
351                 mat.setFloat("Shininess", shinines);
352             } else {
353                 mat.setFloat("Shininess", 16f); // set shininess to some value anyway..
354             }
355 
356             if (vcolor)
357                 mat.setBoolean("UseVertexColor", true);
358 
359             if (textures[0] != null)
360                 mat.setTexture("DiffuseMap", textures[0]);
361 
362             mat.setBoolean("UseMaterialColors", true);
363             if(diffuse != null){
364                 mat.setColor("Diffuse",  diffuse);
365             }else{
366                 mat.setColor("Diffuse", ColorRGBA.White);
367             }
368 
369             if(ambient != null){
370                 mat.setColor("Ambient",  ambient);
371             }else{
372                 mat.setColor("Ambient", ColorRGBA.DarkGray);
373             }
374 
375             if(specular != null){
376                 mat.setColor("Specular", specular);
377             }else{
378                 mat.setColor("Specular", ColorRGBA.Black);
379             }
380 
381             if (emissive != null){
382                 mat.setColor("GlowColor", emissive);
383             }
384         }else{
385             if (vcolor) {
386                 mat.setBoolean("VertexColor", true);
387             }
388 
389             if (textures[0] != null && textures[1] == null){
390                 if (separateTexCoord){
391                     mat.setTexture("LightMap", textures[0]);
392                     mat.setBoolean("SeparateTexCoord", true);
393                 }else{
394                     mat.setTexture("ColorMap", textures[0]);
395                 }
396             }else if (textures[1] != null){
397                 mat.setTexture("ColorMap", textures[0]);
398                 mat.setTexture("LightMap", textures[1]);
399                 if (separateTexCoord){
400                     mat.setBoolean("SeparateTexCoord", true);
401                 }
402             }
403 
404             if(diffuse != null){
405                 mat.setColor("Color", diffuse);
406             }
407 
408             if (emissive != null){
409                 mat.setColor("GlowColor", emissive);
410             }
411         }
412 
413         noLight = false;
414         Arrays.fill(textures, null);
415         diffuse = null;
416         specular = null;
417         shinines = 0f;
418         vcolor = false;
419         blend = false;
420         texUnit = 0;
421         separateTexCoord = false;
422         return mat;
423     }
424 
load(AssetManager assetManager, AssetKey key, InputStream in)425     private MaterialList load(AssetManager assetManager, AssetKey key, InputStream in) throws IOException{
426         folderName = key.getFolder();
427         this.assetManager = assetManager;
428 
429         MaterialList list = null;
430         List<Statement> statements = BlockLanguageParser.parse(in);
431 
432         for (Statement statement : statements){
433             if (statement.getLine().startsWith("import")){
434                 MaterialExtensionSet matExts = null;
435                 if (key instanceof OgreMaterialKey){
436                      matExts = ((OgreMaterialKey)key).getMaterialExtensionSet();
437                 }
438 
439                 if (matExts == null){
440                     throw new IOException("Must specify MaterialExtensionSet when loading\n"+
441                                           "Ogre3D materials with extended materials");
442                 }
443 
444                 list = new MaterialExtensionLoader().load(assetManager, key, matExts, statements);
445                 break;
446             }else if (statement.getLine().startsWith("material")){
447                 if (list == null){
448                     list = new MaterialList();
449                 }
450                 String[] split = statement.getLine().split(" ", 2);
451                 matName = split[1].trim();
452                 readMaterial(statement);
453                 Material mat = compileMaterial();
454                 list.put(matName, mat);
455             }
456         }
457 
458         return list;
459     }
460 
load(AssetInfo info)461     public Object load(AssetInfo info) throws IOException {
462         InputStream in = null;
463         try {
464             in = info.openStream();
465             return load(info.getManager(), info.getKey(), in);
466         } finally {
467             if (in != null){
468                 in.close();
469             }
470         }
471     }
472 
473 }
474