1 /*
2 
3 	Copyright (C) 1991-2001 and beyond by Bungie Studios, Inc.
4 	and the "Aleph One" developers.
5 
6 	This program is free software; you can redistribute it and/or modify
7 	it under the terms of the GNU General Public License as published by
8 	the Free Software Foundation; either version 3 of the License, or
9 	(at your option) any later version.
10 
11 	This program is distributed in the hope that it will be useful,
12 	but WITHOUT ANY WARRANTY; without even the implied warranty of
13 	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 	GNU General Public License for more details.
15 
16 	This license is contained in the file "COPYING",
17 	which is included with this source code; it is available online at
18 	http://www.gnu.org/licenses/gpl.html
19 
20 	Overhead-Map OpenGL Class Implementation
21 	by Loren Petrich,
22 	August 3, 2000
23 
24 	Subclass of OverheadMapClass for doing rendering with OpenGL
25 	Code originally from OGL_Map.c; font handling is still MacOS-specific.
26 
27 [Notes from OGL_Map.c]
28 	This is for drawing the Marathon overhead map with OpenGL, because at large resolutions,
29 	the main CPU can be too slow for this.
30 
31 	Much of this is cribbed from overhead_map_macintosh.c and translated into OpenGL form
32 
33 July 9, 2000:
34 
35 	Complete this OpenGL renderer. I had to add a font-info cache, so as to avoid
36 	re-generating the fonts for every frame. The font glyphs and offsets are stored
37 	as display lists, which appears to be very efficient.
38 
39 July 16, 2000:
40 
41 	Added begin/end pairs for line and polygon rendering; the purpose of these is to allow
42 	more efficient caching.
43 
44 Jul 17, 2000:
45 
46 	Paths now cached and drawn as a single line strip per path.
47 	Lines now cached and drawn in groups with the same width and color;
48 		that has yielded a significant performance improvement.
49 	Same for the polygons, but with relatively little improvement.
50 [End notes]
51 
52 Aug 6, 2000 (Loren Petrich):
53 	Added perimeter drawing to drawing commands for the player object;
54 	this guarantees that this object will always be drawn reasonably correctly
55 
56 Oct 13, 2000 (Loren Petrich)
57 	Converted the various lists into Standard Template Library vectors
58 
59 Jan 25, 2002 (Br'fin (Jeremy Parsons)):
60 	Added TARGET_API_MAC_CARBON for AGL.h
61 */
62 
63 #include <math.h>
64 #include <string.h>
65 
66 #include "cseries.h"
67 #include "OverheadMap_OGL.h"
68 #include "map.h"
69 #include "screen.h"
70 
71 #ifdef HAVE_OPENGL
72 
73 #ifdef HAVE_OPENGL
74 #include "OGL_Headers.h"
75 #include "OGL_Render.h"
76 #endif
77 
78 
79 
80 // rgb_color straight to OpenGL
SetColor(rgb_color & Color)81 static inline void SetColor(rgb_color& Color)
82 {
83 	if (map_is_translucent())
84 		glColor4us(Color.red, Color.green, Color.blue, 32767);
85 	else
86 		glColor3usv((unsigned short *)(&Color));
87 }
88 
89 // Need to test this so as to find out when the color changes
ColorsEqual(rgb_color & Color1,rgb_color & Color2)90 static inline bool ColorsEqual(rgb_color& Color1, rgb_color& Color2)
91 {
92 	return
93 		((Color1.red == Color2.red) &&
94 			(Color1.green == Color2.green) &&
95 				(Color1.blue == Color2.blue));
96 }
97 
98 
99 // For marking out the area to be blanked out when starting rendering;
100 // these are defined in OGL_Render.cpp
101 extern short ViewWidth, ViewHeight;
102 
begin_overall()103 void OverheadMap_OGL_Class::begin_overall()
104 {
105 
106 	// Blank out the screen
107 	// Do that by painting a black polygon
108 	if (!map_is_translucent())
109 	{
110 		glColor3f(0,0,0);
111 		OGL_RenderRect(0, 0, ViewWidth, ViewHeight);
112 	}
113 
114 /*
115 	glEnable(GL_SCISSOR_TEST);	// Don't erase the HUD
116 	glClearColor(0,0,0,0);
117 	glClear(GL_COLOR_BUFFER_BIT);
118 	glDisable(GL_SCISSOR_TEST);
119 */
120 
121 	// Here's for the overhead map
122 	glDisable(GL_DEPTH_TEST);
123 	glDisable(GL_ALPHA_TEST);
124 	if (map_is_translucent())
125 		glEnable(GL_BLEND);
126 	else
127 		glDisable(GL_BLEND);
128 	glDisable(GL_TEXTURE_2D);
129 	glDisable(GL_FOG);
130 	glDisableClientState(GL_TEXTURE_COORD_ARRAY);
131 }
132 
end_overall()133 void OverheadMap_OGL_Class::end_overall()
134 {
135 	glEnableClientState(GL_TEXTURE_COORD_ARRAY);
136 }
137 
138 
begin_polygons()139 void OverheadMap_OGL_Class::begin_polygons()
140 {
141 	// Polygons are rendered before lines, and use the endpoint array,
142 	// so both of them will have it set here. Using the compiled-vertex extension,
143 	// however, makes everything the same color :-P
144 	glVertexPointer(2,GL_SHORT,GetVertexStride(),GetFirstVertex());
145 
146 	// Reset color defaults
147 	SavedColor.red = SavedColor.green = SavedColor.blue = 0;
148 	SetColor(SavedColor);
149 
150 	// Reset cache to zero length
151 	PolygonCache.clear();
152 }
153 
draw_polygon(short vertex_count,short * vertices,rgb_color & color)154 void OverheadMap_OGL_Class::draw_polygon(
155 	short vertex_count,
156 	short *vertices,
157 	rgb_color& color)
158 {
159 	// Test whether the polygon parameters have changed
160 	bool AreColorsEqual = ColorsEqual(color,SavedColor);
161 
162 	// If any change, then draw the cached lines with the *old* parameters,
163 	// Set the new parameters
164 	if (!AreColorsEqual)
165 	{
166 		DrawCachedPolygons();
167 		SavedColor = color;
168 		SetColor(SavedColor);
169 	}
170 
171 	// Implement the polygons as triangle fans
172 	for (int k=2; k<vertex_count; k++)
173 	{
174 		PolygonCache.push_back(vertices[0]);
175 		PolygonCache.push_back(vertices[k-1]);
176 		PolygonCache.push_back(vertices[k]);
177 	}
178 
179 	// glDrawElements(GL_POLYGON,vertex_count,GL_UNSIGNED_SHORT,vertices);
180 }
181 
end_polygons()182 void OverheadMap_OGL_Class::end_polygons()
183 {
184 	DrawCachedPolygons();
185 }
186 
DrawCachedPolygons()187 void OverheadMap_OGL_Class::DrawCachedPolygons()
188 {
189 	glDrawElements(GL_TRIANGLES, PolygonCache.size(),
190 		GL_UNSIGNED_SHORT, PolygonCache.data());
191 	PolygonCache.clear();
192 }
193 
begin_lines()194 void OverheadMap_OGL_Class::begin_lines()
195 {
196 	// Reset color and pen size to defaults
197 	SetColor(SavedColor);
198 	SavedPenSize = 1;
199 
200 	// Reset cache to zero length
201 	LineCache.clear();
202 }
203 
204 
draw_line(short * vertices,rgb_color & color,short pen_size)205 void OverheadMap_OGL_Class::draw_line(
206 	short *vertices,
207 	rgb_color& color,
208 	short pen_size)
209 {
210 	// Test whether the line parameters have changed
211 	bool AreColorsEqual = ColorsEqual(color,SavedColor);
212 	bool AreLinesEquallyWide = (pen_size == SavedPenSize);
213 
214 	// If any change, then draw the cached lines with the *old* parameters
215 	if (!AreColorsEqual || !AreLinesEquallyWide) DrawCachedLines();
216 
217 	// Set the new parameters
218 	if (!AreColorsEqual)
219 	{
220 		SavedColor = color;
221 		SetColor(SavedColor);
222 	}
223 
224 	if (!AreLinesEquallyWide)
225 	{
226 		SavedPenSize = pen_size;
227 	}
228 
229 	// Add the line's points to the cached line
230 	LineCache.push_back(GetVertex(vertices[0]));
231 	LineCache.push_back(GetVertex(vertices[1]));
232 }
233 
end_lines()234 void OverheadMap_OGL_Class::end_lines()
235 {
236 	DrawCachedLines();
237 }
238 
DrawCachedLines()239 void OverheadMap_OGL_Class::DrawCachedLines()
240 {
241 	OGL_RenderLines(LineCache, SavedPenSize);
242 	LineCache.clear();
243 }
244 
245 
draw_thing(world_point2d & center,rgb_color & color,short shape,short radius)246 void OverheadMap_OGL_Class::draw_thing(
247 	world_point2d& center,
248 	rgb_color& color,
249 	short shape,
250 	short radius)
251 {
252 	SetColor(color);
253 
254 	// Let OpenGL do the transformation work
255 	glMatrixMode(GL_MODELVIEW);
256 	glPushMatrix();
257 	glTranslatef(center.x,center.y,0);
258 	glScalef(radius, radius, 1);
259 
260 	switch(shape)
261 	{
262 	case _rectangle_thing:
263 		{
264 			OGL_RenderRect(-0.75f, -0.75f, 1.5f, 1.5f);
265 		}
266 		break;
267 	case _circle_thing:
268 		{
269 			GLfloat ft = 0.1f;
270 			GLfloat ht = ft * 0.5f;
271 			GLfloat vertices[36] = {
272 				-0.30f - ht, -0.75f,
273 				-0.30f + ht, -0.75f + ft,
274 				+0.30f + ht, -0.75f,
275 				+0.30f - ht, -0.75f + ft,
276 				+0.75f - ft, -0.30f + ht,
277 				+0.75f,      -0.30f - ht,
278 				+0.75f - ft, +0.30f - ht,
279 				+0.75f,      +0.30f + ht,
280 				+0.30f - ht, +0.75f - ft,
281 				+0.30f + ht, +0.75f,
282 				-0.30f + ht, +0.75f - ft,
283 				-0.30f - ht, +0.75f,
284 				-0.75f + ft, +0.30f - ht,
285 				-0.75f,      +0.30f + ht,
286 				-0.75f + ft, -0.30f + ht,
287 				-0.75f,      -0.30f - ht,
288 				-0.30f - ht, -0.75f,
289 				-0.30f + ht, -0.75f + ft
290 			};
291 			glVertexPointer(2, GL_FLOAT, 0, vertices);
292 			glDrawArrays(GL_TRIANGLE_STRIP, 0, 36);
293 		}
294 		break;
295 	default:
296 		break;
297 	}
298 	glPopMatrix();
299 }
300 
draw_player(world_point2d & center,angle facing,rgb_color & color,short shrink,short front,short rear,short rear_theta)301 void OverheadMap_OGL_Class::draw_player(
302 	world_point2d& center,
303 	angle facing,
304 	rgb_color& color,
305 	short shrink,
306 	short front,
307 	short rear,
308 	short rear_theta)
309 {
310 	SetColor(color);
311 
312 	// The player is a simple triangle
313 	GLfloat PlayerShape[3][2];
314 
315 	double rear_theta_rads = rear_theta*(8*atan(1.0)/FULL_CIRCLE);
316 	float rear_x = (float)(rear*cos(rear_theta_rads));
317 	float rear_y = (float)(rear*sin(rear_theta_rads));
318 	PlayerShape[0][0] = front;
319 	PlayerShape[0][1] = 0;
320 	PlayerShape[1][0] = rear_x;
321 	PlayerShape[1][1] = rear_y;
322 	PlayerShape[2][0] = rear_x;
323 	PlayerShape[2][1] = - rear_y;
324 
325 	// Let OpenGL do the transformation work
326 	glMatrixMode(GL_MODELVIEW);
327 	glPushMatrix();
328 	glTranslatef(center.x,center.y,0);
329 	glRotatef(facing*(360.0F/FULL_CIRCLE),0,0,1);
330 	float scale = 1/float(1 << shrink);
331 	glScalef(scale,scale,1);
332 	glDisable(GL_TEXTURE_2D);
333 	glDisableClientState(GL_TEXTURE_COORD_ARRAY);
334 	glVertexPointer(2,GL_FLOAT,0,PlayerShape[0]);
335 	glDrawArrays(GL_POLYGON,0,3);
336 
337 	glPopMatrix();
338 }
339 
340 
341 // Text justification: 0=left, 1=center
draw_text(world_point2d & location,rgb_color & color,char * text,FontSpecifier & FontData,short justify)342 void OverheadMap_OGL_Class::draw_text(
343 	world_point2d& location,
344 	rgb_color& color,
345 	char *text,
346 	FontSpecifier& FontData,
347 	short justify)
348 {
349 	// Find the left-side location
350 	world_point2d left_location = location;
351 	switch(justify)
352 	{
353 	case _justify_left:
354 		break;
355 
356 	case _justify_center:
357 		left_location.x -= (FontData.TextWidth(text)>>1);
358 		break;
359 
360 	default:
361 		return;
362 	}
363 
364 	// Set color and location
365 	SetColor(color);
366 
367 	glMatrixMode(GL_MODELVIEW);
368 	glPushMatrix();
369 	glLoadIdentity();
370 	glTranslatef(left_location.x,left_location.y,0);
371 	FontData.OGL_Render(text);
372 	glPopMatrix();
373 }
374 
set_path_drawing(rgb_color & color)375 void OverheadMap_OGL_Class::set_path_drawing(rgb_color& color)
376 {
377 	SetColor(color);
378 }
379 
draw_path(short step,world_point2d & location)380 void OverheadMap_OGL_Class::draw_path(
381 	short step,	// 0: first point
382 	world_point2d &location)
383 {
384 	// At first step, reset the length
385 	if (step <= 0) PathPoints.clear();
386 
387 	// Duplicate points to form lines at each step
388 	if (PathPoints.size() > 1)
389 		PathPoints.push_back(PathPoints.back());
390 
391 	// Add the point
392 	PathPoints.push_back(location);
393 }
394 
finish_path()395 void OverheadMap_OGL_Class::finish_path()
396 {
397 	OGL_RenderLines(PathPoints, 1);
398 	PathPoints.clear();
399 }
400 #endif // def HAVE_OPENGL
401