View Javadoc
1   /*
2    * Created on 2005-01-02
3    *
4    * 1.6:
5    *  - wczytywanie koordynat tekstur z pliku i mozliwośc odczytu ich z zewnątrz
6    * 1.5:
7    * 	- wczytywanie materiałów i tekstur z pliku
8    */
9   package org.sourceforge.jvb3d.Loader;
10  
11  import java.io.File;
12  import java.io.IOException;
13  import java.util.HashMap;
14  import java.util.LinkedList;
15  import java.util.List;
16  import java.util.Map;
17  import java.util.logging.Logger;
18  import javax.media.j3d.Appearance;
19  import javax.media.j3d.Texture;
20  import javax.media.j3d.TextureAttributes;
21  import javax.media.j3d.TextureUnitState;
22  import javax.vecmath.TexCoord4f;
23  import javax.xml.parsers.DocumentBuilderFactory;
24  import javax.xml.parsers.ParserConfigurationException;
25  
26  import org.w3c.dom.Document;
27  import org.w3c.dom.Element;
28  import org.w3c.dom.NamedNodeMap;
29  import org.w3c.dom.NodeList;
30  import org.xml.sax.SAXException;
31  
32  /***
33   * @author Łukasz Krzyżak
34   * 
35   * klasa wczytuje definicje wyglądu poszczególnych powierzchni, i na ich
36   * podstawie generuje odpowiednie obiekty java3d
37   */
38  public class AppearanceFactory {
39  	protected final static Logger logger = Logger
40  			.getLogger("SceneLoader.AppearanceFactory");
41  
42  	class SurfaceInfo {
43  		AppearanceInfo[] wallAppearances = new AppearanceInfo[6];
44  
45  		AppearanceInfo defaultAppearance = null;
46  
47  		/***
48  		 * zwraca obiekt Appearance przypisany do wybranej ściany powierzchni.
49  		 * Jeśli przypisano jakiś wygląd - zwracany jest ten przypisany, jeśli
50  		 * nie - zwracany jest wygląd defaultowy
51  		 * 
52  		 * @param wallId
53  		 *            ID ściany
54  		 * @return wygląd ściany
55  		 */
56  		public Appearance getAppearance(int wallId) {
57  			if (wallAppearances[wallId] != null)
58  				return wallAppearances[wallId].getAppearance();
59  			return defaultAppearance.getAppearance();
60  		}
61  
62  		/***
63  		 * zwraca koordynaty tekstur dla określonej ściany
64  		 * @param wallID numer ściany
65  		 * @return tablica koordynat tekstur - 4 wartości dla kazdej warstwy
66  		 */
67  		public TexCoord4f[] getTextureCoordinates(int wallID) {
68  			if (wallAppearances[wallID] != null)
69  				return wallAppearances[wallID].getTextureCoordinates();
70  			
71  			return defaultAppearance.getTextureCoordinates();
72  		}
73  
74  		/***
75  		 * parsuje dane z drzewa DOM xml, i na ich podstawie tworzy opis
76  		 * powierzchni
77  		 * 
78  		 * @param surfaceRoot
79  		 *            korzeń zawierający informację o powierzchni
80  		 */
81  		public SurfaceInfo(Element surfaceRoot) {
82  			NodeList surfaceElements = surfaceRoot.getChildNodes();
83  
84  			for (int i = 0; i < surfaceElements.getLength(); i++) {
85  				if (surfaceElements.item(i).getNodeName() == "Default")
86  					defaultAppearance = new AppearanceInfo(
87  							(Element) surfaceElements.item(i));
88  				else if (surfaceElements.item(i).getNodeName() == "Wall") {
89  					Element wallElement = (Element) surfaceElements.item(i);
90  					wallAppearances[Integer.parseInt(wallElement
91  							.getAttribute("id"))] = new AppearanceInfo(
92  							wallElement);
93  				}
94  			}
95  		}
96  	}
97  
98  	class AppearanceInfo {
99  		protected String materialId = null;
100 
101 		protected List<TextureInfo> textures = new LinkedList<TextureInfo>();
102 
103 		protected Appearance appearance = null;
104 
105 		/***
106 		 * tworzy nowy opis obiektu Appearance na podstawie danych odczytanych z
107 		 * drzewa DOM xml'a
108 		 * 
109 		 * @param appearanceNode
110 		 *            węzeł będący korzeniem dla opisu wyglądu - " <Default>"
111 		 *            bądź " <Wall>"
112 		 */
113 		public AppearanceInfo(Element appearanceNode) {
114 			Element materialElement = (Element) appearanceNode
115 					.getElementsByTagName("Material").item(0);
116 			if (materialElement != null)
117 				materialId = materialElement.getAttribute("id");
118 
119 			Element textureRoot = (Element) appearanceNode
120 					.getElementsByTagName("Textures").item(0);
121 			if (textureRoot != null) {
122 				NodeList texturesList = textureRoot
123 						.getElementsByTagName("Texture");
124 
125 				for (int i = 0; i < texturesList.getLength(); i++) {
126 					Element texture = (Element) texturesList.item(i);
127 
128 					textures.add(new TextureInfo(texture.getAttribute("id"),
129 							Integer.parseInt(texture.getAttribute("level")),
130 							(Element) texture.getElementsByTagName(
131 									"TextureAttributes").item(0)));
132 				}
133 			}
134 		}
135 
136 		/***
137 		 * zwraca obiekt Appearance opisywany przez obiekt tej klasy. Jeśli
138 		 * jeszcze nie istniał - jest tworzony nowy
139 		 * 
140 		 * @return obiekt Appearance
141 		 */
142 		public Appearance getAppearance() {
143 			if (appearance != null)
144 				return appearance;
145 
146 			appearance = new Appearance();
147 
148 			if (materialId != null)
149 				appearance.setMaterial(MaterialManager.getInstance()
150 						.getMateralById(materialId));
151 
152 			if (textures.size() == 1) {
153 				appearance.setTexture(textures.get(0).getTexture());
154 				appearance
155 						.setTextureAttributes(textures.get(0).getAttributes());
156 			}
157 
158 			if (textures.size() > 1) {
159 				appearance.setTextureUnitState(new TextureUnitState[textures
160 						.size()]);
161 
162 				for (TextureInfo texture : textures) {
163 					TextureUnitState textureState = new TextureUnitState();
164 					textureState.setTexture(texture.getTexture());
165 					textureState.setTextureAttributes(texture.getAttributes());
166 					appearance.setTextureUnitState(texture.textureLevel,
167 							textureState);
168 				}
169 			}
170 			return appearance;
171 		}
172 
173 		/***
174 		 * zwraca tablicę współrzędnych koordynat dla wszystkich poziomów
175 		 * teksturowania
176 		 * 
177 		 * @return tablica wartości współrzędnych w postaci Tuple4f x0, y0, x1,
178 		 *         y1
179 		 */
180 		public TexCoord4f[] getTextureCoordinates() {
181 			if (textures.isEmpty())
182 				return null;
183 
184 			TexCoord4f[] coordinates = new TexCoord4f[textures.size()];
185 			for (TextureInfo texture : textures)
186 				coordinates[texture.textureLevel] = texture
187 						.getTextureCoordinates();
188 
189 			return coordinates;
190 		}
191 	}
192 
193 	class TextureInfo {
194 		protected String textureID = null;
195 
196 		protected int textureMode = 0;
197 
198 		int textureLevel = 0;
199 
200 		protected TextureAttributes attributes = null;
201 
202 		protected TexCoord4f textureCoordinates = null;
203 
204 		/***
205 		 * zwraca obiekt tekstury pobrany z TextureManagera
206 		 * 
207 		 * @return obiekt tekstury
208 		 * @throws NullPointerException
209 		 *             jeśli nie wczytano ID tekstury z xml'a
210 		 */
211 		public Texture getTexture() {
212 			if (textureID == null)
213 				throw new NullPointerException();
214 
215 			return TextureManager.getInstance().getTextureById(textureID);
216 		}
217 
218 		/***
219 		 * zwraca obiekt atrybutów tekstury zgodny z wcześniej sparsowanym
220 		 * opisem
221 		 * 
222 		 * @return obiekt atrybutów tekstury
223 		 */
224 		public TextureAttributes getAttributes() {
225 			if (attributes != null)
226 				return attributes;
227 			attributes = new TextureAttributes();
228 			attributes.setTextureMode(textureMode);
229 			return attributes;
230 		}
231 
232 		/***
233 		 * zwraca koordynaty tekstury odczytane z konfiguracji
234 		 * 
235 		 * @return zestaw współrzędnych
236 		 */
237 		public TexCoord4f getTextureCoordinates() {
238 			return textureCoordinates;
239 		}
240 
241 		/***
242 		 * konstruktor zczytujący dane z DOM xml'a, i wypełniający swoje pola
243 		 * 
244 		 * @param id
245 		 *            id tekstury której dotyczą te informacje
246 		 * @param level
247 		 *            poziom tekstury
248 		 * @param textureAttributes
249 		 *            element zawierający opis atrybutów " <TextureAttributes>"
250 		 */
251 		public TextureInfo(String id, int level, Element textureAttributes) {
252 			textureID = id;
253 			textureLevel = level;
254 			String mode = textureAttributes.getAttribute("mode");
255 
256 			if (mode.equals("blend"))
257 				textureMode = TextureAttributes.BLEND;
258 			else if (mode.equals("replace"))
259 				textureMode = TextureAttributes.REPLACE;
260 			else if (mode.equals("modulate"))
261 				textureMode = TextureAttributes.MODULATE;
262 			else if (mode.equals("decal"))
263 				textureMode = TextureAttributes.DECAL;
264 			else if (mode.equals("combine"))
265 				textureMode = TextureAttributes.COMBINE;
266 			else
267 				logger.warning("Texture " + id
268 						+ " has unknown or no blending mode");
269 			Element textureCoordinatesElement = (Element) textureAttributes
270 					.getElementsByTagName("TextureCoordinates").item(0);
271 
272 			if (textureCoordinatesElement != null) {
273 				NamedNodeMap texCoord = textureCoordinatesElement
274 						.getAttributes();
275 
276 				textureCoordinates = new TexCoord4f(Float.parseFloat(texCoord
277 						.getNamedItem("u0").getNodeValue()),
278 						Float.parseFloat(texCoord.getNamedItem("v0")
279 								.getNodeValue()), Float.parseFloat(texCoord
280 								.getNamedItem("u1").getNodeValue()), Float
281 								.parseFloat(texCoord.getNamedItem("v1")
282 										.getNodeValue()));
283 			}
284 
285 		}
286 	}
287 
288 	protected Map<String, SurfaceInfo> surfaces = new HashMap<String, SurfaceInfo>();
289 
290 	protected static AppearanceFactory instance = new AppearanceFactory();
291 
292 	protected static final String surfacesFile = "data/surfaces.xml";
293 
294 	/***
295 	 * singleton - zwraca instancję
296 	 * @return instancja
297 	 */
298 	public static AppearanceFactory getInstance() {
299 		return instance;
300 	}
301 
302 	protected AppearanceFactory() {
303 		try {
304 			parseSurfacesData();
305 		} catch (Exception e) {
306 			e.printStackTrace();
307 		}
308 	}
309 
310 	protected void parseSurfacesData() throws SAXException, IOException,
311 			ParserConfigurationException {
312 		Document dataDocument = DocumentBuilderFactory.newInstance()
313 				.newDocumentBuilder().parse(new File(surfacesFile));
314 
315 		Element root = (Element) dataDocument.getElementsByTagName("Surfaces")
316 				.item(0);
317 		NodeList surfacesList = root.getElementsByTagName("Surface");
318 
319 		for (int i = 0; i < surfacesList.getLength(); i++) {
320 			Element surface = (Element) surfacesList.item(i);
321 
322 			SurfaceInfo surfaceInfo = new SurfaceInfo(surface);
323 
324 			surfaces.put(surface.getAttribute("id"), surfaceInfo);
325 		}
326 	}
327 
328 	/***
329 	 * na podstawie id powierzchni i ściany generuje obiekt Appearance
330 	 * 
331 	 * @param surfaceID
332 	 *            ID powierzchni
333 	 * @param wallID
334 	 *            ID ściany powierzchni
335 	 * @return obiekt Appearance
336 	 */
337 	public Appearance newAppearance(String surfaceID, int wallID) {
338 		SurfaceInfo surface = surfaces.get(surfaceID);
339 		if (surface == null)
340 			surface = surfaces.get("default");
341 		//throw new NoSuchElementException("Surface " + surfaceID
342 		//		+ "not found in data files");
343 
344 		return surface.getAppearance(wallID);
345 	}
346 
347 	/***
348 	 * zwraca współrzędne tekstury określonej powierzchni i ściany
349 	 * @param surfaceID id powierzchni
350 	 * @param wallId id ściany
351 	 * @return tablica współrzędnych
352 	 */
353 	public TexCoord4f[] getTextureCoordinates(String surfaceID, int wallId) {
354 		SurfaceInfo surface = surfaces.get(surfaceID);
355 		if (surface == null)
356 			surface = surfaces.get("default");
357 
358 		return surface.getTextureCoordinates(wallId);
359 
360 	}
361 }