1
2
3
4
5
6
7
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
342
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 }