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