View Javadoc

1   package nl.tudelft.goal.ut2004.visualizer.timeline.map;
2   
3   import static javax.media.opengl.GL.GL_LINEAR;
4   import static javax.media.opengl.GL.GL_LINES;
5   import static javax.media.opengl.GL.GL_TEXTURE_2D;
6   import static javax.media.opengl.GL.GL_TEXTURE_MAG_FILTER;
7   import static javax.media.opengl.GL.GL_TEXTURE_MIN_FILTER;
8   import static javax.media.opengl.GL.GL_TRIANGLES;
9   import static javax.media.opengl.GL2.GL_COMPILE;
10  import static javax.media.opengl.GL2.GL_QUADS;
11  import static javax.media.opengl.fixedfunc.GLLightingFunc.GL_COLOR_MATERIAL;
12  import static javax.media.opengl.fixedfunc.GLLightingFunc.GL_FLAT;
13  import static javax.media.opengl.fixedfunc.GLLightingFunc.GL_SMOOTH;
14  
15  import java.awt.Color;
16  import java.nio.ByteBuffer;
17  import java.util.Collection;
18  import java.util.LinkedList;
19  import java.util.List;
20  import java.util.prefs.PreferenceChangeEvent;
21  import java.util.prefs.PreferenceChangeListener;
22  import java.util.prefs.Preferences;
23  
24  import javax.media.opengl.GL;
25  import javax.media.opengl.GL2;
26  import javax.media.opengl.glu.GLU;
27  
28  import nl.tudelft.goal.ut2004.visualizer.map.BlendTriangle;
29  import nl.tudelft.goal.ut2004.visualizer.map.BlendVertex;
30  import nl.tudelft.goal.ut2004.visualizer.options.MapFlag;
31  import cz.cuni.amis.pogamut.base3d.worldview.object.Location;
32  import cz.cuni.amis.pogamut.unreal.communication.worldview.map.Box;
33  import cz.cuni.amis.pogamut.unreal.communication.worldview.map.IUnrealMap;
34  import cz.cuni.amis.pogamut.unreal.communication.worldview.map.IUnrealMapInfo;
35  import cz.cuni.amis.pogamut.unreal.communication.worldview.map.IUnrealWaylink;
36  import cz.cuni.amis.pogamut.unreal.communication.worldview.map.IUnrealWaypoint;
37  
38  /**
39   * Renderer of map. Because of uncomplete server implementation I have no way of
40   * knowing state of the server, so I hope this will work.
41   * 
42   * I *assume* that server is up and running and I can get worldmap from it.
43   * 
44   * @author Honza
45   */
46  public class MapRenderer implements ISubGLRenderer<IUnrealMap> {
47  
48  	private static final Color HIGH_COLOR_DEFAULT = Color.WHITE;
49  	private static final String HIGH_COLOR_KEY = "HIGH_COLOR_KEY";
50  	private static final Color LOW_COLOR_DEFAULT = Color.LIGHT_GRAY;
51  	private static final String LOW_COLOR_KEY = "LOW_COLOR_KEY";
52  
53  	public final int GRID_SCALE = 1000;
54  	public final double NAVPOINT_RADIUS = 30;
55  
56  	/**
57  	 * OpenGL display lists
58  	 */
59  	private int gridList = -1;
60  	private int pathDisplayList = -1;
61  	private int backgroundList = -1;
62  
63  	/**
64  	 * Flag that we should update display lists according to new data from
65  	 * preferences.
66  	 */
67  	private boolean updateLists = true;
68  
69  	private IUnrealMap map;
70  	/**
71  	 * List of all triangles used for rendering paths between
72  	 */
73  	private List<PathTriangle> pathTris;
74  
75  	private int glName;
76  
77  	private static Preferences preferences = Preferences.userNodeForPackage(MapRenderer.class);
78  
79  	private PreferenceChangeListener changeListener = new PreferenceChangeListener() {
80  
81  		@Override
82  		public void preferenceChange(PreferenceChangeEvent evt) {
83  			updateLists = true;
84  		}
85  	};
86  
87  	/**
88  	 * GameBots provides us with flags about pathways between navpoints. This
89  	 * class is human readable names for flags.
90  	 * 
91  	 * The reason why is this class and not enum is that it is a bitmap mask so
92  	 * they can easily combine. For now.
93  	 */
94  	public MapRenderer(IUnrealMap map, int glName) {
95  		this.map = map;
96  		this.glName = glName;
97  		preferences.addPreferenceChangeListener(changeListener);
98  	}
99  
100 	@Override
101 	public IUnrealMap getObject() {
102 		return map;
103 	}
104 
105 	/**
106 	 * Precreate display lists for map, because map can be quite large and it
107 	 * would be troublesome to do it every rendering.
108 	 * 
109 	 * @param gl
110 	 */
111 	@Override
112 	public void prepare(GL gl) {
113 		gridList = createGridList(gl);
114 		backgroundList = createMapBackground(gl);
115 		pathTris = createPathsList();
116 
117 	}
118 
119 	/**
120 	 * Create a diplay list for map background image, i.e. image that is show
121 	 * above grid to give a better idea about world. It is mostly screenshot
122 	 * from UnrealEd.
123 	 * 
124 	 * @param gl
125 	 * @return id of display list
126 	 */
127 	public int createMapBackground(GL gla) {
128 		GL2 gl = gla.getGL2();
129 		GLU glu = new GLU();
130 
131 		IUnrealMapInfo info = map.getInfo();
132 
133 		if (info == null) {
134 			return -1;
135 		}
136 
137 		Location[] pos2D = info.getImagePoints();// new Location[3];
138 		Location[] posMap = info.getWorldPoints();// new Location[3];
139 
140 		for (int i = 0; i < posMap.length; i++) {
141 			posMap[i] = posMap[i].setZ(0);
142 		}
143 
144 		// Chci pozice rohu obrazku ve 3d
145 		Location vec1stTo2nd = Location.sub(pos2D[1], pos2D[0]);
146 		Location vec1stTo3rd = Location.sub(pos2D[2], pos2D[0]);
147 
148 		// get position in 3d for every corner
149 		Coeficients[] coef = new Coeficients[4];
150 		// tlc ~ top left corner
151 		coef[0] = solveEquation(new Location(0, 0, 0), pos2D[0], vec1stTo2nd, vec1stTo3rd);
152 		// trc
153 		coef[1] = solveEquation(new Location(info.getWidth(), 0, 0), pos2D[0], vec1stTo2nd, vec1stTo3rd);
154 		// brc
155 		coef[2] = solveEquation(new Location(info.getWidth(), info.getHeight(), 0), pos2D[0], vec1stTo2nd, vec1stTo3rd);
156 		// blc
157 		coef[3] = solveEquation(new Location(0, info.getHeight(), 0), pos2D[0], vec1stTo2nd, vec1stTo3rd);
158 
159 		Location map1stTo2nd = Location.sub(posMap[1], posMap[0]);
160 		Location map1stTo3rd = Location.sub(posMap[2], posMap[0]);
161 
162 		Location[] mapLoc = new Location[4];
163 
164 		for (int i = 0; i < 4; i++) {
165 			mapLoc[i] = Location.add(posMap[0], Location.add(map1stTo2nd.scale(coef[i].a), map1stTo3rd.scale(coef[i].b)));
166 		}
167 
168 		int texture = genTexture(gl);
169 
170 		gl.glBindTexture(GL.GL_TEXTURE_2D, texture);
171 
172 		glu.gluBuild2DMipmaps(GL.GL_TEXTURE_2D, GL.GL_RGB8, info.getWidth(), info.getHeight(), GL.GL_RGB, GL.GL_UNSIGNED_BYTE,
173 				ByteBuffer.wrap(info.getImgRGBData()));
174 
175 		gl.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
176 		gl.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
177 
178 		int list = gl.glGenLists(1);
179 
180 		// start new list
181 		gl.glNewList(list, GL_COMPILE);
182 
183 		gl.glEnable(GL_TEXTURE_2D);
184 
185 		gl.glBindTexture(GL_TEXTURE_2D, texture);
186 
187 		gl.glBegin(GL_QUADS);
188 
189 		gl.glColor3d(1, 1, 1);
190 
191 		int i = 0;
192 		double z = getFloorZ() + 5;
193 		gl.glTexCoord2d(0, 1);
194 		gl.glVertex3d(mapLoc[i].x, mapLoc[i].y, z);
195 
196 		i = 1;
197 		gl.glTexCoord2d(1, 1);
198 		gl.glVertex3d(mapLoc[i].x, mapLoc[i].y, z);
199 
200 		i = 2;
201 		gl.glTexCoord2d(1, 0);
202 		gl.glVertex3d(mapLoc[i].x, mapLoc[i].y, z);
203 
204 		i = 3;
205 		gl.glTexCoord2d(0, 0);
206 		gl.glVertex3d(mapLoc[i].x, mapLoc[i].y, z);
207 
208 		gl.glEnd();
209 
210 		gl.glDisable(GL.GL_TEXTURE_2D);
211 
212 		gl.glEndList();
213 
214 		return list;
215 	}
216 
217 	/**
218 	 * Generate one texture
219 	 * 
220 	 * @param gl
221 	 * @return id of texture
222 	 */
223 	private int genTexture(GL gl) {
224 		int[] textures = new int[1];
225 		gl.glGenTextures(1, textures, 0);
226 		return textures[0];
227 	}
228 
229 	private double getFloorZ() {
230 		Box box = map.getBox();
231 		return box.minZ - box.getMinDelta() * 0.20;
232 	}
233 
234 	private double getGridZ() {
235 		Box box = map.getBox();
236 		return box.minZ - box.getMinDelta() * 0.35;
237 	}
238 
239 	private static class Coeficients {
240 
241 		public Coeficients(double a, double b) {
242 			this.a = a;
243 			this.b = b;
244 		}
245 
246 		double a, b;
247 	}
248 
249 	/**
250 	 * get vector components so R = P+a*U +b*V
251 	 * 
252 	 * @return
253 	 */
254 	private Coeficients solveEquation(Location r, Location p, Location u, Location v) {
255 		/*
256 		 * r.x = p.x + a*u.x + b*v.x r.y = p.y + a*u.y + b*v.y
257 		 */
258 		if (u.x != 0) {
259 			double multi = u.y / u.x;
260 			/*
261 			 * 0 = (p.x - r.x) * multi + a*u.x * multi + b*v.x * multi 0 = (p.y
262 			 * - r.y) + a*u.y + b*v.y
263 			 * 
264 			 * 0 = (p.y - r.y) - (p.x - r.x) * multi + b*v.y - b*v.x * multi
265 			 */
266 			double b = (-((p.y - r.y) - (p.x - r.x) * multi)) / (v.y - v.x * multi);
267 
268 			// 0 = (p.x - a.x) + a*u.x + b*v.x
269 			double a = -((p.x - r.x) + b * v.x) / u.x;
270 
271 			return new Coeficients(a, b);
272 		} else {
273 			/*
274 			 * r.x = p.x + b*v.x r.y = p.y + a*u.y + b*v.y
275 			 */
276 			double b = (r.x - p.x) / v.x;
277 			double a = (r.y - p.y - b * v.y) / u.y;
278 			return new Coeficients(a, b);
279 		}
280 
281 	}
282 
283 	/**
284 	 * Return list of triangles that (if rendered) displays all waypoints in the
285 	 * map. Waypoints are represented as circle with radius
286 	 * {@link NAVPOINT_RADIUS} at every waypoint.
287 	 * 
288 	 * @return List of triangles
289 	 */
290 	private LinkedList<BlendTriangle> createWaypointsList() {
291 		LinkedList<BlendTriangle> triangles = new LinkedList<BlendTriangle>();
292 		Collection<IUnrealWaypoint> navs = map.vertexSet();
293 
294 		GlColor color = getWayPointColor();
295 		for (IUnrealWaypoint nav : navs) {
296 			Location loc = nav.getLocation();
297 
298 			Location[] points = createCirclePoints(loc, NAVPOINT_RADIUS);
299 
300 			for (int pointIndex = 0; pointIndex < points.length; pointIndex++) {
301 				BlendTriangle triangle = new BlendTriangle();
302 
303 				triangle.setVertex(0, loc, color);
304 				triangle.setVertex(1, points[pointIndex], color);
305 				triangle.setVertex(2, points[(pointIndex + 1) % points.length], color);
306 
307 				triangles.add(triangle);
308 			}
309 		}
310 
311 		return triangles;
312 	}
313 
314 	private GlColor getWayPointColor() {
315 		// TODO: Use preference here.
316 		return new GlColor(Color.BLUE);
317 	}
318 
319 	/**
320 	 * Return list of points that form a circle with center loc and radius
321 	 * radius.
322 	 * 
323 	 * @param loc
324 	 *            Center of circle
325 	 * @param radius
326 	 *            Radius of circle
327 	 * @return List of points that form the circle
328 	 */
329 	private Location[] createCirclePoints(Location loc, double radius) {
330 		Location[] points = new Location[12];
331 
332 		double stepAngle = 2 * Math.PI / points.length;
333 
334 		for (int pointIndex = 0; pointIndex < points.length; pointIndex++) {
335 			double angle = stepAngle * pointIndex;
336 			double xPos = loc.x + radius * Math.cos(angle);
337 			double yPos = loc.y + radius * Math.sin(angle);
338 			points[pointIndex] = new Location(xPos, yPos, loc.z);
339 		}
340 
341 		return points;
342 	}
343 
344 	/**
345 	 * Create OpenGl list for grid lines of the map.
346 	 * 
347 	 * @return id of a list
348 	 */
349 	private int createGridList(GL gla) {
350 		GL2 gl = gla.getGL2();
351 		Box mapBox = map.getBox();
352 		int numMainLines = getNumGridLines(mapBox);
353 
354 		double lineLength = 2 * GRID_SCALE * numMainLines;
355 		// TODO: Is 10 good arbiotrary number?
356 		double floorZ = getGridZ();
357 		int list = gl.glGenLists(1);
358 
359 		gl.glNewList(list, GL_COMPILE);
360 		{
361 			gl.glBegin(GL_LINES);
362 			{
363 				// central X lines, red
364 				double minY = mapBox.getCenterY() - lineLength / 2;
365 				double maxY = mapBox.getCenterY() + lineLength / 2;
366 
367 				gl.glColor3d(0.45, 0.29, 0.32);
368 				gl.glVertex3d(mapBox.getCenterX(), minY, floorZ);
369 				gl.glVertex3d(mapBox.getCenterX(), maxY, floorZ);
370 
371 				// central Y line, green
372 				double minX = mapBox.getCenterX() - lineLength / 2;
373 				double maxX = mapBox.getCenterX() + lineLength / 2;
374 
375 				gl.glColor3d(0.3, 0.57, 0.31);
376 				gl.glVertex3d(minX, mapBox.getCenterY(), floorZ);
377 				gl.glVertex3d(maxX, mapBox.getCenterY(), floorZ);
378 
379 				// other lines for better idea about size of level
380 				// main lines
381 				for (int line = 1; line <= numMainLines; line++) {
382 					for (int coef = -1; coef <= 1; coef += 2) {
383 						// main lines (darker grey)
384 						gl.glColor3d(0.34, 0.34, 0.34);
385 						// draw along Y axis
386 						gl.glVertex3d(mapBox.getCenterX() + coef * line * GRID_SCALE, minY, floorZ);
387 						gl.glVertex3d(mapBox.getCenterX() + coef * line * GRID_SCALE, maxY, floorZ);
388 						// draw along X axis
389 						gl.glVertex3d(minX, mapBox.getCenterY() + coef * line * GRID_SCALE, floorZ);
390 						gl.glVertex3d(maxX, mapBox.getCenterY() + coef * line * GRID_SCALE, floorZ);
391 
392 						// minor lines (lighter grey)
393 						gl.glColor3d(0.41, 0.41, 0.41);
394 						for (int minority = 1; minority < 10; minority++) {
395 							// draw along Y axis
396 							gl.glVertex3d(mapBox.getCenterX() + coef * ((line - 1) * GRID_SCALE + minority * GRID_SCALE / 10), minY, floorZ);
397 							gl.glVertex3d(mapBox.getCenterX() + coef * ((line - 1) * GRID_SCALE + minority * GRID_SCALE / 10), maxY, floorZ);
398 							// draw along X axis
399 							gl.glVertex3d(minX, mapBox.getCenterY() + coef * ((line - 1) * GRID_SCALE + minority * GRID_SCALE / 10), floorZ);
400 							gl.glVertex3d(maxX, mapBox.getCenterY() + coef * ((line - 1) * GRID_SCALE + minority * GRID_SCALE / 10), floorZ);
401 						}
402 					}
403 				}
404 			}
405 			gl.glEnd();
406 		}
407 		gl.glEndList();
408 
409 		return list;
410 	}
411 
412 	/**
413 	 * How many squares (each square is GRID_SCALE big) will grid have from
414 	 * center to border in every direction.
415 	 * 
416 	 * @return Number of squares of the box
417 	 */
418 	private int getNumGridLines(Box mapBox) {
419 		double max = mapBox.getDeltaX() > mapBox.getDeltaY() ? mapBox.getDeltaX() : mapBox.getDeltaY();
420 
421 		max /= 2;
422 		return (int) Math.ceil(max / GRID_SCALE);
423 	}
424 
425 	/**
426 	 * Return list of locations that will represent quads
427 	 * 
428 	 * @param path
429 	 *            array of location[i*4], i is some number, currently 3, but it
430 	 *            depends on structure of connection
431 	 */
432 	private Location[] createQuadPath(IUnrealWaylink path) {
433 		Location[] quads = new Location[3 * 4];
434 
435 		IUnrealWaypoint from = path.getStart();
436 		IUnrealWaypoint to = path.getEnd();
437 
438 		Location fromLoc = from.getLocation();
439 		Location toLoc = to.getLocation();
440 
441 		// get normalized direction from fromNav to toNav in x,y plane.
442 		Location dir = Location.sub(toLoc, fromLoc);
443 		dir = dir.setZ(0);
444 		dir = dir.getNormalized();
445 
446 		Location trans = new Location(dir.y, -dir.x, 0);
447 
448 		// now do the quad to cover circle part of fromNav
449 		quads[0] = Location.add(fromLoc, trans.scale(NAVPOINT_RADIUS));
450 		quads[1] = Location.add(quads[0], dir.scale(NAVPOINT_RADIUS));
451 		quads[2] = Location.add(quads[1], trans.scale(-2 * NAVPOINT_RADIUS));
452 		quads[3] = Location.add(quads[2], dir.scale(-NAVPOINT_RADIUS));
453 
454 		// quad that is covering to toNav
455 		quads[4] = Location.add(toLoc, trans.scale(-NAVPOINT_RADIUS));
456 		quads[5] = Location.add(quads[4], dir.scale(-NAVPOINT_RADIUS));
457 		quads[6] = Location.add(quads[5], trans.scale(2 * NAVPOINT_RADIUS));
458 		quads[7] = Location.add(quads[6], dir.scale(NAVPOINT_RADIUS));
459 
460 		quads[8] = quads[2];
461 		quads[9] = quads[1];
462 		quads[10] = quads[6];
463 		quads[11] = quads[5];
464 
465 		return quads;
466 	}
467 
468 	private static class PathTriangle extends BlendTriangle {
469 
470 		private int flags;
471 
472 		public PathTriangle(int flags) {
473 			this.flags = flags;
474 		}
475 
476 		public int getFlags() {
477 			return flags;
478 		}
479 	}
480 
481 	private LinkedList<PathTriangle> createPathsList() {
482 		LinkedList<PathTriangle> triangles = new LinkedList<PathTriangle>();
483 		Collection<IUnrealWaylink> paths = map.edgeSet();
484 
485 		double deltaZ = this.map.getBox().getDeltaZ();
486 		double displaceZ = this.map.getBox().minZ;
487 
488 		for (IUnrealWaylink path : paths) {
489 			Location[] quads = createQuadPath(path);
490 
491 			GlColor lowColor = new GlColor(0.8, 0.8, 0.8);
492 			GlColor highColor = new GlColor(0.8, 0, 0);
493 
494 			// put quads to the list of blend triangles
495 			int quadNum = quads.length / 4;
496 			for (int quad = 0; quad < quadNum; quad++) {
497 				PathTriangle triOne = new PathTriangle(path.getFlags());
498 
499 				for (int i = 0; i < 3; i++) {
500 					Location vertexLoc = quads[quad * 4 + i];
501 					GlColor color = lowColor.getMixedWith(highColor, (vertexLoc.z - displaceZ) / deltaZ);
502 					triOne.setVertex(i, vertexLoc, color);
503 				}
504 
505 				PathTriangle triTwo = new PathTriangle(path.getFlags());
506 				for (int i = 0; i < 3; i++) {
507 					int quadIndex = quad * 4 + ((i + 2) % 4);
508 					Location vertexLoc = quads[quadIndex];
509 					GlColor color = lowColor.getMixedWith(highColor, (vertexLoc.z - displaceZ) / deltaZ);
510 					triTwo.setVertex(i, vertexLoc, color);
511 				}
512 
513 				triangles.add(triOne);
514 				triangles.add(triTwo);
515 			}
516 		}
517 		return triangles;
518 	}
519 
520 	@Override
521 	public synchronized void render(GL gla) {
522 		GL2 gl = gla.getGL2();
523 
524 		/*
525 		 * After a while it seems that using lighting and blending produces
526 		 * worse results than this, at least in lucidity.
527 		 * 
528 		 * float[] lightAmbient = new float[]{0.5f, 0.5f, 0.5f, 1.0f}; float[]
529 		 * lightDiffuse = new float[]{1.0f, 1.0f, 1.0f, 1.0f}; float[]
530 		 * lightPosition = new float[]{ 0, 0, 1210,//0, 0, 0, //
531 		 * (float)levelBox.getFlag().getCenterX(), //
532 		 * (float)levelBox.getFlag().getCenterY(), //
533 		 * (float)levelBox.getFlag().getCenterZ() +
534 		 * (float)levelBox.getFlag().getDeltaZ(), 1.0f};
535 		 * gl.glLightfv(GL.GL_LIGHT0, GL.GL_AMBIENT,
536 		 * FloatBuffer.wrap(lightAmbient)); gl.glLightfv(GL.GL_LIGHT0,
537 		 * GL.GL_DIFFUSE, FloatBuffer.wrap(lightDiffuse));
538 		 * gl.glLightfv(GL.GL_LIGHT0, GL.GL_POSITION,
539 		 * FloatBuffer.wrap(lightPosition)); gl.glEnable(GL.GL_LIGHT0);
540 		 * 
541 		 * gl.glLightfv(GL.GL_LIGHT0, GL.GL_SPOT_DIRECTION, new float[]{0, 0,
542 		 * 1}, 0);
543 		 */
544 
545 		if (updateLists || !gl.glIsList(pathDisplayList)) {
546 			updateMapDisplayLists(gl);
547 			updateLists = false;
548 		}
549 
550 		gl.glLoadName(glName);
551 
552 		// Rendering like this is too CPU intensive, so using display lists
553 		// renderPaths(gl, pathTris);
554 		// renderWaypoints(gl, waypointsTris);
555 
556 		// render grid and background
557 		gl.glShadeModel(GL_FLAT);
558 		gl.glCallList(gridList);
559 		gl.glCallList(backgroundList);
560 		gl.glCallList(pathDisplayList);
561 
562 		gl.glLoadName(-1);
563 	}
564 
565 	/**
566 	 * Render triangles stored in pathTriangles with info from settings
567 	 * 
568 	 * @param gl
569 	 */
570 	private synchronized void renderPaths(GL gla, List<PathTriangle> triangles) {
571 		GL2 gl = gla.getGL2();
572 		// Get colors from preferences
573 		GlColor lowColor = new GlColor(getLowColor());
574 		GlColor highColor = new GlColor(getHighColor());
575 
576 		boolean includeFlagBehavior = getIncludePathsFlag();
577 
578 		double deltaZ = this.map.getBox().getDeltaZ();
579 		double displaceZ = this.map.getBox().minZ;
580 
581 		gl.glEnable(GL_COLOR_MATERIAL);
582 		gl.glShadeModel(GL_SMOOTH);
583 
584 		gl.glBegin(GL_TRIANGLES);
585 		for (PathTriangle triangle : triangles) {
586 			boolean render = false;
587 			if (includeFlagBehavior) {
588 				render = includeCanRenderPathFlag(triangle.getFlags());
589 			} else {
590 				render = excludeCanRenderFlag(triangle.getFlags());
591 			}
592 
593 			if (render) {
594 				for (BlendVertex v : triangle.getVerts()) {
595 					Location vertexLoc = v.getLocation();
596 					GlColor color = lowColor.getMixedWith(highColor, (vertexLoc.z - displaceZ) / deltaZ);
597 
598 					gl.glColor4d(color.r, color.g, color.b, color.a);
599 					gl.glVertex3d(vertexLoc.x, vertexLoc.y, vertexLoc.z);
600 				}
601 			}
602 		}
603 		gl.glEnd();
604 	}
605 
606 	private boolean getIncludePathsFlag() {
607 		// TODO(MP): User a preference provider
608 		return true;
609 	}
610 
611 	public static Color getHighColor() {
612 		int rgb = preferences.getInt(HIGH_COLOR_KEY, HIGH_COLOR_DEFAULT.getRGB());
613 		return new Color(rgb);
614 	}
615 
616 	public static void setHighColor(Color c) {
617 		preferences.putInt(HIGH_COLOR_KEY, c.getRGB());
618 	}
619 
620 	public static Color getLowColor() {
621 		int rgb = preferences.getInt(LOW_COLOR_KEY, LOW_COLOR_DEFAULT.getRGB());
622 		return new Color(rgb);
623 	}
624 
625 	public static void setLowColor(Color c) {
626 		preferences.putInt(LOW_COLOR_KEY, c.getRGB());
627 	}
628 
629 	/**
630 	 * If testedFlags has flag that according to preferences should be drawn,
631 	 * draw it
632 	 * 
633 	 * @param flag
634 	 * @return true if at least one of flags in testedFlag is set and
635 	 *         preferences says that we should render it
636 	 */
637 	private synchronized boolean includeCanRenderPathFlag(int testedFlag) {
638 		for (MapFlag flag : MapFlag.values()) {
639 			// if tested flag has enabled the flag
640 			if ((flag.getFlag() & testedFlag) != 0) {
641 				// if it does, does user says we should render such paths
642 				boolean shouldRender = getShouldRender();
643 				if (shouldRender) {
644 					return true;
645 				}
646 			}
647 		}
648 		return false;
649 	}
650 
651 	private boolean getShouldRender() {
652 		// TODO(MP:) Use a preference provider here.
653 		return true;
654 	}
655 
656 	/**
657 	 * If testedFlags has flag that according to preferences shouldn't be drawn,
658 	 * don't render.
659 	 * 
660 	 * @param testedFlag
661 	 * @return
662 	 */
663 	private synchronized boolean excludeCanRenderFlag(int testedFlag) {
664 		for (MapFlag flag : MapFlag.values()) {
665 			// if tested flag has enabled the flag
666 			if ((flag.getFlag() & testedFlag) != 0) {
667 				// if it does, does user says we should render such paths
668 				boolean shouldRender = getShouldRender();
669 				if (!shouldRender) {
670 					return false;
671 				}
672 			}
673 		}
674 		return true;
675 	}
676 
677 	/**
678 	 * Render all waypoints (the circles in the map), data generated in
679 	 * createWaypointsList
680 	 * 
681 	 * @param gl
682 	 * @param triangles
683 	 */
684 	private synchronized void renderWaypoints(GL gla, List<BlendTriangle> triangles) {
685 		GL2 gl = gla.getGL2();
686 		GlColor color = getWayPointColor();
687 
688 		gl.glEnable(GL_COLOR_MATERIAL);
689 		gl.glShadeModel(GL_SMOOTH);
690 
691 		gl.glBegin(GL_TRIANGLES);
692 		for (BlendTriangle triangle : triangles) {
693 			for (BlendVertex v : triangle.getVerts()) {
694 				// take color according to width
695 				gl.glColor4d(color.r, color.g, color.b, color.a);
696 				gl.glVertex3d(v.getLocation().x, v.getLocation().y, v.getLocation().z + 0.1);
697 			}
698 		}
699 		gl.glEnd();
700 	}
701 
702 	/**
703 	 * Update display lists for waypoints and path quads according to
704 	 * preferences
705 	 */
706 	private synchronized void updateMapDisplayLists(GL gla) {
707 		GL2 gl = gla.getGL2();
708 
709 		// delete old
710 		gl.glDeleteLists(pathDisplayList, 1);
711 
712 		// create new
713 		pathDisplayList = gl.glGenLists(1);
714 		gl.glNewList(pathDisplayList, GL_COMPILE);
715 		renderPaths(gl, pathTris);
716 		gl.glEndList();
717 
718 	}
719 
720 	/**
721 	 * Clean up the component (listeners, contexts ect.)
722 	 */
723 	public void destroy() {
724 		preferences.removePreferenceChangeListener(changeListener);
725 	}
726 
727 	@Override
728 	public int getGLName() {
729 		return 0;
730 	}
731 }