View Javadoc

1   package nl.tudelft.goal.ut2004.visualizer.timeline.map;
2   
3   import java.awt.Color;
4   import java.util.ArrayList;
5   import java.util.List;
6   import java.util.prefs.PreferenceChangeEvent;
7   import java.util.prefs.PreferenceChangeListener;
8   import java.util.prefs.Preferences;
9   
10  import javax.media.opengl.GL;
11  import javax.media.opengl.GL2;
12  import javax.media.opengl.glu.GLU;
13  import javax.media.opengl.glu.GLUquadric;
14  
15  import nl.tudelft.goal.ut2004.visualizer.map.TeamShade;
16  
17  import com.jogamp.opengl.util.gl2.GLUT;
18  
19  import cz.cuni.amis.pogamut.base3d.worldview.object.Location;
20  import cz.cuni.amis.pogamut.base3d.worldview.object.Rotation;
21  import cz.cuni.amis.pogamut.unreal.communication.messages.gbinfomessages.IPlayer;
22  
23  /**
24   * Sub-renderer for object {@link IRenderableUTAgent}
25   * 
26   * <b>Implementation note:</b> be careful when asking twice for same field of
27   * agent (like agent.getRotation()), because it is dependent on time when you
28   * ask and returned value is not guaranteed to be same (like first can be valid
29   * and second null).
30   * 
31   * @author Honza
32   */
33  public class PlayerRenderer implements ISubGLRenderer<IPlayer> {
34  
35  	private final double SPHERE_RADIUS = 60;
36  	private final int SPHERE_SLICES = 32;
37  	private final int SPHERE_STACKS = 32;
38  
39  	private static final Color BLUE_TEAM_COLOR_DEFAULT = Color.BLUE;
40  	private static final Color RED_TEAM_COLOR_DEFAULT = Color.RED;
41  
42  	private static final String BLUE_TEAM_COLOR_KEY = "BLUE_TEAM_COLOR_KEY";
43  	private static final String RED_TEAM_COLOR_KEY = "RED_TEAM_COLOR_KEY";
44  
45  	private static final Preferences preferences = Preferences.userNodeForPackage(PlayerRenderer.class);
46  	private PreferenceChangeListener changeListener = new PreferenceChangeListener() {
47  
48  		@Override
49  		public void preferenceChange(PreferenceChangeEvent evt) {
50  			dirty = true;
51  			color.setBlueTeam(getBlueTeamColor());
52  			color.setRedTeam(getRedTeamColor());
53  
54  		}
55  	};
56  	private boolean dirty = true;
57  
58  	private final int glName;
59  	private final IPlayer agent;
60  	private final TeamShade color;
61  
62  	/**
63  	 * Create a new subrenderer with passed agent as source of data.
64  	 * 
65  	 * @param renderableUTAgent
66  	 *            agent used as source of data.
67  	 */
68  	public PlayerRenderer(IPlayer utAgent, int glName) {
69  		this.agent = utAgent;
70  		this.glName = glName;
71  		this.color = new TeamShade(getRedTeamColor(), getBlueTeamColor());
72  		preferences.addPreferenceChangeListener(changeListener);
73  
74  	}
75  
76  	@Override
77  	public void prepare(GL gl) {
78  
79  	}
80  
81  	@Override
82  	public IPlayer getObject() {
83  		return agent;
84  	}
85  
86  	@Override
87  	public void render(GL gla) {
88  		GL2 gl = gla.getGL2();
89  
90  		try {
91  			Location entityLocation = agent.getLocation();
92  			if (entityLocation == null) {
93  				return;
94  			}
95  
96  			Location center = new Location(entityLocation.x, entityLocation.y, entityLocation.z + SPHERE_RADIUS * 1.1);
97  			GlColor color = new GlColor(getColor());
98  
99  			gl.glLoadName(glName);
100 			renderAgent(gl, color, center);
101 			gl.glLoadName(-1);
102 			
103 			renderInfo(gl, color, center);
104 
105 
106 		} catch (RuntimeException e) {
107 			e.printStackTrace();
108 			// TODO handle situation when an agent disconnects
109 		}
110 	}
111 
112 	/**
113 	 * Render agent at specified position
114 	 * 
115 	 * @param gl
116 	 * @param position
117 	 */
118 	private void renderAgent(GL gla, GlColor color, Location position) {
119 		final GLU glu = new GLU();
120 		final GLUquadric quadratic = glu.gluNewQuadric();
121 
122 		GL2 gl = gla.getGL2();
123 
124 		gl.glPushMatrix();
125 		{
126 			gl.glTranslated(position.x, position.y, position.z);
127 			// draw sphere
128 			gl.glColor4d(color.r, color.g, color.b, color.a);
129 			glu.gluSphere(quadratic, SPHERE_RADIUS, SPHERE_SLICES, SPHERE_STACKS);
130 
131 		}
132 		gl.glPopMatrix();
133 
134 		Rotation rot = agent.getRotation();
135 		if (rot != null) {
136 			renderRotation(gl, new GlColor(1, 0, 0), position, rot);
137 		}
138 
139 	}
140 
141 	/**
142 	 * Draw rotation arrow
143 	 * 
144 	 * @param gl
145 	 * @param color
146 	 *            What color should arrow be
147 	 * @param center
148 	 *            Where is center of arrow
149 	 * @param rotation
150 	 *            In what direction does arrow points
151 	 */
152 	private void renderRotation(GL gla, GlColor color, Location center, Rotation rotation) {
153 		final GLUT glut = new GLUT();
154 		GL2 gl = gla.getGL2();
155 
156 		gl.glPushMatrix();
157 		{
158 			gl.glTranslated(center.x, center.y, center.z);
159 
160 			Location endOfArrow = rotation.toLocation().getNormalized().scale(SPHERE_RADIUS * 2.5);
161 
162 			gl.glBegin(GL.GL_LINES);
163 			gl.glColor4d(color.r, color.g, color.b, color.a);
164 			gl.glVertex3d(0, 0, 0);
165 			gl.glVertex3d(endOfArrow.x, endOfArrow.y, endOfArrow.z);
166 			gl.glEnd();
167 
168 			gl.glTranslated(endOfArrow.x, endOfArrow.y, endOfArrow.z);
169 			// XXX: This works only in 2D, not 3D, because I am not in the mood
170 			// to figure out direction of Roll, Yaw and Pitch as well as order
171 			// of
172 			// transformations. And rotation.toLocation() returns 2D coords
173 			// anyway.
174 
175 			double yaw = rotation.getYaw() / 32767 * 180; // left right, aka
176 															// around z
177 			double roll = rotation.getRoll() / 32767 * 180; // clockwise/counter?
178 															// around x
179 			double pitch = rotation.getPitch() / 32767 * 180; // up and down,
180 																// around y
181 
182 			/*
183 			 * gl.glRotated(pitch, ); gl.glRotated(yaw, ); gl.glRotated(roll, );
184 			 */
185 			// return res.mul(pitch).mul(yaw).mul(roll);
186 
187 			// gl.glRotated(roll, 1,0,0);
188 			gl.glRotated(yaw, 0, 0, 1);
189 			// gl.glRotated(pitch, 0,1,0);
190 
191 			gl.glRotated(90, 0, 1, 0);
192 
193 			glut.glutSolidCone(20, 40, 16, 16);
194 		}
195 		gl.glPopMatrix();
196 
197 	}
198 	
199 	/**
200 	 * Render info about agent (in most cases event messages) and its name.
201 	 * TODO: Ugly code, refactor
202 	 * 
203 	 * @param gl
204 	 * @param color
205 	 *            What color should be used to render info.
206 	 * @param location
207 	 *            position of agent
208 	 */
209 	private void renderInfo(GL gla, GlColor color, Location location) {
210 		final GLU glu = new GLU();
211 		final GLUT glut = new GLUT();
212 
213 		GL2 gl = gla.getGL2();
214 
215 		// get text
216 		List<String> infos = new ArrayList<String>();
217 		infos.add(0, '*' + agent.getName() + '*');
218 
219 		Location topHead = new Location(location.x, location.y, location.z + 2 * SPHERE_RADIUS * 1.1);
220 
221 		Location top2d = GLTools.getScreenCoordinates(gl, glu, topHead);
222 
223 		int lineGap = 12;
224 		int font = GLUT.BITMAP_HELVETICA_10;
225 
226 		int maxWidth = 0;
227 		for (String line : infos) {
228 			int lineWidth = glut.glutBitmapLength(font, line);
229 			if (lineWidth > maxWidth) {
230 				maxWidth = lineWidth;
231 			}
232 		}
233 
234 		// update starting position
235 		top2d = new Location(top2d.x - maxWidth / 2, top2d.y + (infos.size() - 1) * lineGap, top2d.z);
236 
237 		GlColor textColor = color.getMixedWith(new GlColor(0, 0, 0), 80);
238 
239 		gl.glColor3d(textColor.r, textColor.g, textColor.b);
240 		for (int i = 0; i < infos.size(); i++) {
241 			String text = infos.get(i);
242 			if (i == 0) {
243 				gl.glColor3d(color.r, color.g, color.b);
244 			} else {
245 				gl.glColor3d(textColor.r, textColor.g, textColor.b);
246 				// gl.glColor3d(0, 0, 0);
247 			}
248 			Location textPos = GLTools.getWorldCoordinates(gl, glu, top2d);
249 			gl.glRasterPos3d(textPos.x, textPos.y, textPos.z);
250 			glut.glutBitmapString(font, text);
251 
252 			top2d = top2d.addY(-lineGap);
253 		}
254 	}
255 
256 	public Color getColor() {
257 		return color.getColor(agent.getTeam());
258 	}
259 
260 	public static Color getRedTeamColor() {
261 		int rgb = preferences.getInt(RED_TEAM_COLOR_KEY, RED_TEAM_COLOR_DEFAULT.getRGB());
262 		return new Color(rgb);
263 	}
264 
265 	public static void setRedTeamColor(Color c) {
266 		preferences.putInt(RED_TEAM_COLOR_KEY, c.getRGB());
267 	}
268 
269 	public static Color getBlueTeamColor() {
270 		int rgb = preferences.getInt(BLUE_TEAM_COLOR_KEY, BLUE_TEAM_COLOR_DEFAULT.getRGB());
271 		return new Color(rgb);
272 	}
273 
274 	public static void setBlueTeamColor(Color c) {
275 		preferences.putInt(BLUE_TEAM_COLOR_KEY, c.getRGB());
276 	}
277 
278 	@Override
279 	public int getGLName() {
280 		return glName;
281 	}
282 	@Override
283 	public void destroy() {
284 		preferences.removePreferenceChangeListener(changeListener);
285 	}
286 }