1 /*
2 * Copyright (C) Volition, Inc. 1999. All rights reserved.
3 *
4 * All source code herein is the property of Volition, Inc. You may not sell
5 * or otherwise commercially exploit the source or things you created based on the
6 * source.
7 *
8 */
9
10
11
12 #ifdef _WIN32
13 #include <windows.h>
14 #include <windowsx.h>
15 #endif
16
17 #include <limits.h>
18
19 #include "globalincs/pstypes.h"
20 #include "osapi/osapi.h"
21 #include "graphics/2d.h"
22 #include "graphics/grstub.h"
23 #include "render/3d.h"
24 #include "bmpman/bmpman.h"
25 #include "palman/palman.h"
26 #include "graphics/font.h"
27 #include "graphics/grinternal.h"
28 #include "globalincs/systemvars.h"
29 #include "cmdline/cmdline.h"
30 #include "graphics/grbatch.h"
31 #include "parse/scripting.h"
32 #include "gamesequence/gamesequence.h" //WMC - for scripting hooks in gr_flip()
33 #include "io/keycontrol.h" // m!m
34
35
36 #if defined(SCP_UNIX) && !defined(__APPLE__)
37 #if ( SDL_VERSION_ATLEAST(1, 2, 7) )
38 #include "SDL_cpuinfo.h"
39 #endif
40 #endif // SCP_UNIX && !__APPLE__
41
42 // Includes for different rendering systems
43 #include "graphics/gropengl.h"
44
45 const char *Resolution_prefixes[GR_NUM_RESOLUTIONS] = { "", "2_" };
46
47 screen gr_screen;
48
49 color_gun Gr_red, Gr_green, Gr_blue, Gr_alpha;
50 color_gun Gr_t_red, Gr_t_green, Gr_t_blue, Gr_t_alpha;
51 color_gun Gr_ta_red, Gr_ta_green, Gr_ta_blue, Gr_ta_alpha;
52 color_gun *Gr_current_red, *Gr_current_green, *Gr_current_blue, *Gr_current_alpha;
53
54
55 ubyte Gr_original_palette[768]; // The palette
56 ubyte Gr_current_palette[768];
57 char Gr_current_palette_name[128] = NOX("none");
58
59 // cursor stuff
60 int Gr_cursor = -1;
61 int Web_cursor_bitmap = -1;
62 int Gr_cursor_size = 32; // default w/h
63
64 int Gr_inited = 0;
65
66 uint Gr_signature = 0;
67
68 float Gr_gamma = 1.8f;
69 int Gr_gamma_int = 180;
70
71 // z-buffer stuff
72 int gr_zbuffering = 0;
73 int gr_zbuffering_mode = 0;
74 int gr_global_zbuffering = 0;
75
76 // stencil buffer stuff
77 int gr_stencil_mode = 0;
78
79 // alpha mask stuff
80 int gr_alpha_test = 0;
81
82 // Default clipping distances
83 const float Default_min_draw_distance = 1.0f;
84 const float Default_max_draw_distance = 1e10;
85 float Min_draw_distance = Default_min_draw_distance;
86 float Max_draw_distance = Default_max_draw_distance;
87
88 static int GL_cursor_nframes = 0;
89
90 // Pre-computed screen resize vars
91 static float Gr_full_resize_X = 1.0f, Gr_full_resize_Y = 1.0f;
92 static float Gr_resize_X = 1.0f, Gr_resize_Y = 1.0f;
93 static float Gr_menu_offset_X = 0.0f, Gr_menu_offset_Y = 0.0f;
94
95 float Gr_save_full_resize_X = 1.0f, Gr_save_full_resize_Y = 1.0f;
96 float Gr_save_resize_X = 1.0f, Gr_save_resize_Y = 1.0f;
97 float Gr_save_menu_offset_X = 0.0f, Gr_save_menu_offset_Y = 0.0f;
98
99 bool Save_custom_screen_size;
100
gr_set_screen_scale(int w,int h)101 void gr_set_screen_scale(int w, int h)
102 {
103 Gr_full_resize_X = (float)gr_screen.max_w / (float)w;
104 Gr_full_resize_Y = (float)gr_screen.max_h / (float)h;
105
106 if (!Cmdline_stretch_menu) {
107 float aspect_quotient = ((float)gr_screen.max_w / (float)gr_screen.max_h) / ((float)w / (float)h);
108
109 Gr_resize_X = Gr_full_resize_X / ((aspect_quotient > 1.0f) ? aspect_quotient : 1.0f);
110 Gr_resize_Y = Gr_full_resize_Y * ((aspect_quotient < 1.0f) ? aspect_quotient : 1.0f);
111
112 Gr_menu_offset_X = (aspect_quotient > 1.0f) ? ((gr_screen.max_w - gr_screen.max_w / aspect_quotient) / 2.0f) : 0.0f;
113 Gr_menu_offset_Y = (aspect_quotient < 1.0f) ? ((gr_screen.max_h - gr_screen.max_h * aspect_quotient) / 2.0f) : 0.0f;
114 } else {
115 Gr_resize_X = Gr_full_resize_X;
116 Gr_resize_Y = Gr_full_resize_Y;
117
118 Gr_menu_offset_X = 0.0f;
119 Gr_menu_offset_Y = 0.0f;
120 }
121
122 Save_custom_screen_size = gr_screen.custom_size;
123
124 gr_screen.custom_size = true;
125 }
126
gr_set_screen_scale(int w,int h,int max_w,int max_h)127 void gr_set_screen_scale(int w, int h, int max_w, int max_h)
128 {
129 Gr_resize_X = Gr_full_resize_X = (float)max_w / (float)w;
130 Gr_resize_Y = Gr_full_resize_Y = (float)max_h / (float)h;
131
132 Gr_menu_offset_X = 0.0f;
133 Gr_menu_offset_Y = 0.0f;
134
135 Save_custom_screen_size = gr_screen.custom_size;
136
137 gr_screen.custom_size = true;
138 }
139
gr_reset_screen_scale()140 void gr_reset_screen_scale()
141 {
142 Gr_full_resize_X = Gr_save_full_resize_X;
143 Gr_full_resize_Y = Gr_save_full_resize_Y;
144
145 Gr_resize_X = Gr_save_resize_X;
146 Gr_resize_Y = Gr_save_resize_Y;
147
148 Gr_menu_offset_X = Gr_save_menu_offset_X;
149 Gr_menu_offset_Y = Gr_save_menu_offset_Y;
150
151 gr_screen.custom_size = Save_custom_screen_size;
152 }
153
154 /**
155 * This function is to be called if you wish to scale GR_1024 or GR_640 x and y positions or
156 * lengths in order to keep the correctly scaled to nonstandard resolutions
157 *
158 * @param x X value, can be NULL
159 * @param y Y value, can be NULL
160 * @param w width, can be NULL
161 * @param h height, can be NULL
162 * @param resize_mode
163 * @return always true unless error
164 */
gr_resize_screen_pos(int * x,int * y,int * w,int * h,int resize_mode)165 bool gr_resize_screen_pos(int *x, int *y, int *w, int *h, int resize_mode)
166 {
167 if ( resize_mode == GR_RESIZE_NONE || (!gr_screen.custom_size && (gr_screen.rendering_to_texture == -1)) ) {
168 return false;
169 }
170
171 float xy_tmp = 0.0f;
172
173 if ( x ) {
174 xy_tmp = (*x) * ((resize_mode == GR_RESIZE_FULL) ? Gr_full_resize_X : Gr_resize_X) + ((resize_mode == GR_RESIZE_MENU) ? Gr_menu_offset_X : 0.0f);
175 (*x) = fl2i(xy_tmp);
176 }
177
178 if ( y ) {
179 xy_tmp = (*y) * ((resize_mode == GR_RESIZE_FULL) ? Gr_full_resize_Y : Gr_resize_Y) + ((resize_mode == GR_RESIZE_MENU) ? Gr_menu_offset_Y : 0.0f);
180 (*y) = fl2i(xy_tmp);
181 }
182
183 if ( w ) {
184 xy_tmp = (*w) * ((resize_mode == GR_RESIZE_FULL) ? Gr_full_resize_X : Gr_resize_X);
185 (*w) = fl2i(xy_tmp);
186 }
187
188 if ( h ) {
189 xy_tmp = (*h) * ((resize_mode == GR_RESIZE_FULL) ? Gr_full_resize_Y : Gr_resize_Y);
190 (*h) = fl2i(xy_tmp);
191 }
192
193 return true;
194 }
195
196 /**
197 *
198 * @param x X value, can be NULL
199 * @param y Y value, can be NULL
200 * @param w width, can be NULL
201 * @param h height, can be NULL
202 * @param resize_mode
203 * @return always true unless error
204 */
gr_unsize_screen_pos(int * x,int * y,int * w,int * h,int resize_mode)205 bool gr_unsize_screen_pos(int *x, int *y, int *w, int *h, int resize_mode)
206 {
207 if ( resize_mode == GR_RESIZE_NONE || (!gr_screen.custom_size && (gr_screen.rendering_to_texture == -1)) ) {
208 return false;
209 }
210
211 float xy_tmp = 0.0f;
212
213 if ( x ) {
214 xy_tmp = ((*x) - ((resize_mode == GR_RESIZE_MENU) ? Gr_menu_offset_X : 0.0f)) / ((resize_mode == GR_RESIZE_FULL) ? Gr_full_resize_X : Gr_resize_X);
215 (*x) = fl2i(xy_tmp);
216 }
217
218 if ( y ) {
219 xy_tmp = ((*y) - ((resize_mode == GR_RESIZE_MENU) ? Gr_menu_offset_Y : 0.0f)) / ((resize_mode == GR_RESIZE_FULL) ? Gr_full_resize_Y : Gr_resize_Y);
220 (*y) = fl2i(xy_tmp);
221 }
222
223 if ( w ) {
224 xy_tmp = (*w) / ((resize_mode == GR_RESIZE_FULL) ? Gr_full_resize_X : Gr_resize_X);
225 (*w) = fl2i(xy_tmp);
226 }
227
228 if ( h ) {
229 xy_tmp = (*h) / ((resize_mode == GR_RESIZE_FULL) ? Gr_full_resize_Y : Gr_resize_Y);
230 (*h) = fl2i(xy_tmp);
231 }
232
233 return true;
234 }
235
236 /**
237 * This function is to be called if you wish to scale GR_1024 or GR_640 x and y positions or
238 * lengths in order to keep the correctly scaled to nonstandard resolutions
239 *
240 * @param x X value, can be NULL
241 * @param y Y value, can be NULL
242 * @param w width, can be NULL
243 * @param h height, can be NULL
244 * @param resize_mode
245 * @return always true unless error
246 */
gr_resize_screen_posf(float * x,float * y,float * w,float * h,int resize_mode)247 bool gr_resize_screen_posf(float *x, float *y, float *w, float *h, int resize_mode)
248 {
249 if ( resize_mode == GR_RESIZE_NONE || (!gr_screen.custom_size && (gr_screen.rendering_to_texture == -1)) ) {
250 return false;
251 }
252
253 float xy_tmp = 0.0f;
254
255 if ( x ) {
256 xy_tmp = (*x) * ((resize_mode == GR_RESIZE_FULL) ? Gr_full_resize_X : Gr_resize_X) + ((resize_mode == GR_RESIZE_MENU) ? Gr_menu_offset_X : 0.0f);
257 (*x) = xy_tmp;
258 }
259
260 if ( y ) {
261 xy_tmp = (*y) * ((resize_mode == GR_RESIZE_FULL) ? Gr_full_resize_Y : Gr_resize_Y) + ((resize_mode == GR_RESIZE_MENU) ? Gr_menu_offset_Y : 0.0f);
262 (*y) = xy_tmp;
263 }
264
265 if ( w ) {
266 xy_tmp = (*w) * ((resize_mode == GR_RESIZE_FULL) ? Gr_full_resize_X : Gr_resize_X);
267 (*w) = xy_tmp;
268 }
269
270 if ( h ) {
271 xy_tmp = (*h) * ((resize_mode == GR_RESIZE_FULL) ? Gr_full_resize_Y : Gr_resize_Y);
272 (*h) = xy_tmp;
273 }
274
275 return true;
276 }
277
278 /**
279 *
280 * @param x X value, can be NULL
281 * @param y Y value, can be NULL
282 * @param w width, can be NULL
283 * @param h height, can be NULL
284 * @param resize_mode
285 * @return always true unless error
286 */
gr_unsize_screen_posf(float * x,float * y,float * w,float * h,int resize_mode)287 bool gr_unsize_screen_posf(float *x, float *y, float *w, float *h, int resize_mode)
288 {
289 if ( resize_mode == GR_RESIZE_NONE || (!gr_screen.custom_size && (gr_screen.rendering_to_texture == -1)) ) {
290 return false;
291 }
292
293 float xy_tmp = 0.0f;
294
295 if ( x ) {
296 xy_tmp = ((*x) - ((resize_mode == GR_RESIZE_MENU) ? Gr_menu_offset_X : 0.0f)) / ((resize_mode == GR_RESIZE_FULL) ? Gr_full_resize_X : Gr_resize_X);
297 (*x) = xy_tmp;
298 }
299
300 if ( y ) {
301 xy_tmp = ((*y) - ((resize_mode == GR_RESIZE_MENU) ? Gr_menu_offset_Y : 0.0f)) / ((resize_mode == GR_RESIZE_FULL) ? Gr_full_resize_Y : Gr_resize_Y);
302 (*y) = xy_tmp;
303 }
304
305 if ( w ) {
306 xy_tmp = (*w) / ((resize_mode == GR_RESIZE_FULL) ? Gr_full_resize_X : Gr_resize_X);
307 (*w) = xy_tmp;
308 }
309
310 if ( h ) {
311 xy_tmp = (*h) / ((resize_mode == GR_RESIZE_FULL) ? Gr_full_resize_Y : Gr_resize_Y);
312 (*h) = xy_tmp;
313 }
314
315 return true;
316 }
317
gr_close()318 void gr_close()
319 {
320 if ( !Gr_inited ) {
321 return;
322 }
323
324 palette_flush();
325
326 switch (gr_screen.mode) {
327 case GR_OPENGL:
328 gr_opengl_cleanup();
329 break;
330
331 case GR_STUB:
332 break;
333
334 default:
335 Int3(); // Invalid graphics mode
336 }
337
338 gr_font_close();
339
340 Gr_inited = 0;
341 }
342
343
344 /**
345 * Set screen clear color
346 */
347 DCF(clear_color, "set clear color r, g, b")
348 {
349 ubyte r, g, b;
350
351 dc_get_arg(ARG_UBYTE);
352 r = Dc_arg_ubyte;
353 dc_get_arg(ARG_UBYTE);
354 g = Dc_arg_ubyte;
355 dc_get_arg(ARG_UBYTE);
356 b = Dc_arg_ubyte;
357
358 // set the color
359 gr_set_clear_color(r, g, b);
360 }
361
gr_set_palette_internal(const char * name,ubyte * palette,int restrict_font_to_128)362 void gr_set_palette_internal( const char *name, ubyte * palette, int restrict_font_to_128 )
363 {
364 if ( palette == NULL ) {
365 // Create a default palette
366 int r,g,b,i;
367 i = 0;
368
369 for (r=0; r<6; r++ )
370 for (g=0; g<6; g++ )
371 for (b=0; b<6; b++ ) {
372 Gr_current_palette[i*3+0] = (unsigned char)(r*51);
373 Gr_current_palette[i*3+1] = (unsigned char)(g*51);
374 Gr_current_palette[i*3+2] = (unsigned char)(b*51);
375 i++;
376 }
377 for ( i=216;i<256; i++ ) {
378 Gr_current_palette[i*3+0] = (unsigned char)((i-216)*6);
379 Gr_current_palette[i*3+1] = (unsigned char)((i-216)*6);
380 Gr_current_palette[i*3+2] = (unsigned char)((i-216)*6);
381 }
382 memmove( Gr_original_palette, Gr_current_palette, 768 );
383 } else {
384 memmove( Gr_original_palette, palette, 768 );
385 memmove( Gr_current_palette, palette, 768 );
386 }
387
388 if ( Gr_inited ) {
389 if (gr_screen.gf_set_palette) {
390 (*gr_screen.gf_set_palette)(Gr_current_palette, restrict_font_to_128 );
391
392 // Since the palette set code might shuffle the palette,
393 // reload it into the source palette
394 if ( palette ) {
395 memmove( palette, Gr_current_palette, 768 );
396 }
397 }
398
399 // Update Palette Manager tables
400 memmove( gr_palette, Gr_current_palette, 768 );
401 palette_update(name, restrict_font_to_128);
402 }
403 }
404
405
gr_set_palette(const char * name,ubyte * palette,int restrict_font_to_128)406 void gr_set_palette( const char *name, ubyte * palette, int restrict_font_to_128 )
407 {
408 char *p;
409 palette_flush();
410 strcpy_s( Gr_current_palette_name, name );
411 p = strchr( Gr_current_palette_name, '.' );
412 if ( p ) *p = 0;
413 gr_screen.signature = Gr_signature++;
414 gr_set_palette_internal( name, palette, restrict_font_to_128 );
415 }
416
gr_screen_resize(int width,int height)417 void gr_screen_resize(int width, int height)
418 {
419 // this should only be called from FRED!!
420 if ( !Fred_running ) {
421 Int3();
422 return;
423 }
424
425 gr_screen.save_max_w = gr_screen.max_w = gr_screen.max_w_unscaled = width;
426 gr_screen.save_max_h = gr_screen.max_h = gr_screen.max_h_unscaled = height;
427
428 gr_screen.offset_x = gr_screen.offset_x_unscaled = 0;
429 gr_screen.offset_y = gr_screen.offset_y_unscaled = 0;
430
431 gr_screen.clip_left = gr_screen.clip_left_unscaled = 0;
432 gr_screen.clip_top = gr_screen.clip_top_unscaled = 0;
433 gr_screen.clip_right = gr_screen.clip_right_unscaled = gr_screen.max_w - 1;
434 gr_screen.clip_bottom = gr_screen.clip_bottom_unscaled = gr_screen.max_h - 1;
435 gr_screen.clip_width = gr_screen.clip_width_unscaled = gr_screen.max_w;
436 gr_screen.clip_height = gr_screen.clip_height_unscaled = gr_screen.max_h;
437 gr_screen.clip_aspect = i2fl(gr_screen.clip_width) / i2fl(gr_screen.clip_height);
438
439 if (gr_screen.custom_size) {
440 gr_unsize_screen_pos( &gr_screen.max_w_unscaled, &gr_screen.max_h_unscaled );
441 gr_unsize_screen_pos( &gr_screen.clip_right_unscaled, &gr_screen.clip_bottom_unscaled );
442 gr_unsize_screen_pos( &gr_screen.clip_width_unscaled, &gr_screen.clip_height_unscaled );
443 }
444
445 gr_screen.save_max_w_unscaled = gr_screen.max_w_unscaled;
446 gr_screen.save_max_h_unscaled = gr_screen.max_h_unscaled;
447
448 if (gr_screen.mode == GR_OPENGL) {
449 extern void opengl_setup_viewport();
450 opengl_setup_viewport();
451 }
452 }
453
gr_init_sub(int mode,int width,int height,int depth)454 static bool gr_init_sub(int mode, int width, int height, int depth)
455 {
456 int res = GR_1024;
457 bool rc = false;
458
459 memset( &gr_screen, 0, sizeof(screen) );
460
461 if ( ((width == 640) && (height == 480)) || ((width == 1024) && (height == 768)) ) {
462 gr_screen.custom_size = false;
463 } else {
464 gr_screen.custom_size = true;
465 }
466
467 if ( (width >= 1024) && (height >= 600) ) {
468 res = GR_1024;
469 } else {
470 res = GR_640;
471 }
472
473 if (Fred_running) {
474 gr_screen.custom_size = false;
475 res = GR_640;
476 mode = GR_OPENGL;
477 }
478
479 Gr_save_full_resize_X = Gr_full_resize_X = (float)width / ((res == GR_1024) ? 1024.0f : 640.0f);
480 Gr_save_full_resize_Y = Gr_full_resize_Y = (float)height / ((res == GR_1024) ? 768.0f : 480.0f);
481
482 if (gr_screen.custom_size && !Cmdline_stretch_menu) {
483 float aspect_quotient = ((float)width / (float)height) / (4.0f / 3.0f);
484
485 Gr_save_resize_X = Gr_resize_X = Gr_full_resize_X / ((aspect_quotient > 1.0f) ? aspect_quotient : 1.0f);
486 Gr_save_resize_Y = Gr_resize_Y = Gr_full_resize_Y * ((aspect_quotient < 1.0f) ? aspect_quotient : 1.0f);
487
488 Gr_save_menu_offset_X = Gr_menu_offset_X = (aspect_quotient > 1.0f) ? ((width - width / aspect_quotient) / 2.0f) : 0.0f;
489 Gr_save_menu_offset_Y = Gr_menu_offset_Y = (aspect_quotient < 1.0f) ? ((height - height * aspect_quotient) / 2.0f) : 0.0f;
490 } else {
491 Gr_save_resize_X = Gr_resize_X = Gr_full_resize_X;
492 Gr_save_resize_Y = Gr_resize_Y = Gr_full_resize_Y;
493
494 Gr_save_menu_offset_X = Gr_menu_offset_X = 0.0f;
495 Gr_save_menu_offset_Y = Gr_menu_offset_Y = 0.0f;
496 }
497
498
499 gr_screen.signature = Gr_signature++;
500 gr_screen.bits_per_pixel = depth;
501 gr_screen.bytes_per_pixel= depth / 8;
502 gr_screen.rendering_to_texture = -1;
503 gr_screen.recording_state_block = false;
504 gr_screen.envmap_render_target = -1;
505 gr_screen.mode = mode;
506 gr_screen.res = res;
507 gr_screen.aspect = 1.0f; // Normal PC screen
508
509 gr_screen.save_max_w = gr_screen.max_w = gr_screen.max_w_unscaled = width;
510 gr_screen.save_max_h = gr_screen.max_h = gr_screen.max_h_unscaled = height;
511
512 gr_screen.offset_x = gr_screen.offset_x_unscaled = 0;
513 gr_screen.offset_y = gr_screen.offset_y_unscaled = 0;
514
515 gr_screen.clip_left = gr_screen.clip_left_unscaled = 0;
516 gr_screen.clip_top = gr_screen.clip_top_unscaled = 0;
517 gr_screen.clip_right = gr_screen.clip_right_unscaled = gr_screen.max_w - 1;
518 gr_screen.clip_bottom = gr_screen.clip_bottom_unscaled = gr_screen.max_h - 1;
519 gr_screen.clip_width = gr_screen.clip_width_unscaled = gr_screen.max_w;
520 gr_screen.clip_height = gr_screen.clip_height_unscaled = gr_screen.max_h;
521 gr_screen.clip_aspect = i2fl(gr_screen.clip_width) / i2fl(gr_screen.clip_height);
522 gr_screen.clip_center_x = (gr_screen.clip_left + gr_screen.clip_right) * 0.5f;
523 gr_screen.clip_center_y = (gr_screen.clip_top + gr_screen.clip_bottom) * 0.5f;
524
525 if (gr_screen.custom_size) {
526 gr_unsize_screen_pos( &gr_screen.max_w_unscaled, &gr_screen.max_h_unscaled );
527 gr_unsize_screen_pos( &gr_screen.clip_right_unscaled, &gr_screen.clip_bottom_unscaled );
528 gr_unsize_screen_pos( &gr_screen.clip_width_unscaled, &gr_screen.clip_height_unscaled );
529 }
530
531 gr_screen.save_max_w_unscaled = gr_screen.max_w_unscaled;
532 gr_screen.save_max_h_unscaled = gr_screen.max_h_unscaled;
533
534 #ifdef WIN32
535 // FRED doesn't need this
536 if ( !Fred_running && !Is_standalone ) {
537 // for Windows, we need to do this just before the *_init() calls
538 extern void win32_create_window(int width, int height);
539 win32_create_window( width, height );
540 }
541 #endif
542
543 switch (mode) {
544 case GR_OPENGL:
545 rc = gr_opengl_init();
546 break;
547 case GR_STUB:
548 rc = gr_stub_init();
549 break;
550 default:
551 Int3(); // Invalid graphics mode
552 }
553
554 if ( !rc ) {
555 return false;
556 }
557
558 return true;
559 }
560
gr_init(int d_mode,int d_width,int d_height,int d_depth)561 bool gr_init(int d_mode, int d_width, int d_height, int d_depth)
562 {
563 int width = 1024, height = 768, depth = 32, mode = GR_OPENGL;
564 const char *ptr = NULL;
565 const char *Default_video_settings = "OGL -(1024x768)x32 bit";
566
567 if ( !Gr_inited ) {
568 atexit(gr_close);
569 }
570
571 // If already inited, shutdown the previous graphics
572 if (Gr_inited) {
573 switch (gr_screen.mode) {
574 case GR_OPENGL:
575 gr_opengl_cleanup();
576 break;
577
578 case GR_STUB:
579 break;
580
581 default:
582 Int3(); // Invalid graphics mode
583 }
584 }
585
586 // We cannot continue without this, quit, but try to help the user out first
587 ptr = os_config_read_string(NULL, NOX("VideocardFs2open"), NULL);
588
589 // if we don't have a config string then construct one, using OpenGL 1024x768 32-bit as the default
590 if (ptr == NULL) {
591 ptr = Default_video_settings;
592 }
593
594 Assert( ptr != NULL );
595
596 // NOTE: The "ptr+5" is to skip over the initial "????-" in the video string.
597 // If the format of that string changes you'll have to change this too!!!
598 if ( sscanf(ptr+5, "(%dx%d)x%d ", &width, &height, &depth) != 3 ) {
599 Error(LOCATION, "Can't understand 'VideocardFs2open' config entry!");
600 }
601
602 if (Cmdline_res != NULL) {
603 int tmp_width = 0;
604 int tmp_height = 0;
605
606 if ( sscanf(Cmdline_res, "%dx%d", &tmp_width, &tmp_height) == 2 ) {
607 width = tmp_width;
608 height = tmp_height;
609 }
610 }
611
612 if (d_mode == GR_DEFAULT) {
613 // OpenGL should be default
614 mode = GR_OPENGL;
615 } else {
616 mode = d_mode;
617 }
618
619 // see if we passed good values, and use those instead of the config settings
620 if ( (d_width != GR_DEFAULT) && (d_height != GR_DEFAULT) ) {
621 width = d_width;
622 height = d_height;
623 }
624
625 if (d_depth != GR_DEFAULT) {
626 depth = d_depth;
627 }
628
629 // check for hi-res interface files so that we can verify our width/height is correct
630 bool has_sparky_hi = (cf_exists_full("2_ChoosePilot-m.pcx", CF_TYPE_ANY) && cf_exists_full("2_TechShipData-m.pcx", CF_TYPE_ANY));
631
632 // if we don't have it then fall back to 640x480 mode instead
633 if ( !has_sparky_hi ) {
634 if ( (width == 1024) && (height == 768) ) {
635 width = 640;
636 height = 480;
637 } else {
638 width = 800;
639 height = 600;
640 }
641 }
642
643 // if we are in standalone mode then just use special defaults
644 if (Is_standalone) {
645 mode = GR_STUB;
646 width = 640;
647 height = 480;
648 depth = 16;
649 }
650
651 // These compiler macros will force windowed mode at the specified resolution if
652 // built in debug mode. This helps if you run with the debugger active as the
653 // game won't be switching from fullscreen to minimized every time you hit a breakpoint or
654 // warning message.
655 #ifdef _DEBUG
656 #ifdef _FORCE_DEBUG_WIDESCREEN
657 width = 1280;
658 height = 800;
659 depth = 32;
660 Cmdline_window = 1;
661 #elif defined(_FORCE_DEBUG_1024)
662 width = 1024;
663 height = 768;
664 depth = 32;
665 Cmdline_window = 1;
666 #elif defined(_FORCE_DEBUG_640)
667 width = 640;
668 height = 480;
669 depth = 32;
670 Cmdline_window = 1;
671 #endif
672 #endif
673
674 // now try to actually init everything...
675 if ( gr_init_sub(mode, width, height, depth) == false ) {
676 return false;
677 }
678
679 gr_set_palette_internal(Gr_current_palette_name, NULL, 0);
680
681 bm_init();
682
683 if (Gr_cursor < 0) {
684 int w, h;
685
686 Gr_cursor = bm_load( "cursor" );
687
688 if (Gr_cursor >= 0) {
689 // get cursor size, so that we can be sure to account for the full thing
690 // in later cursor hiding code
691 bm_get_info(Gr_cursor, &w, &h);
692 Gr_cursor_size = MAX(w, h);
693
694 if (Gr_cursor_size <= 0) {
695 Int3();
696 Gr_cursor_size = 32;
697 }
698 }
699 }
700
701 // load the web pointer cursor bitmap
702 if (Web_cursor_bitmap < 0) {
703 //if it still hasn't loaded then this usually means that the executable isn't in the same directory as the main fs2 install
704 if ( (Web_cursor_bitmap = bm_load_animation("cursorweb")) < 0 ) {
705 Error(LOCATION, "\nWeb cursor bitmap not found. This is most likely due to one of three reasons:\n"
706 "\t1) You're running FreeSpace Open from somewhere other than your FreeSpace 2 folder;\n"
707 "\t2) You've somehow corrupted your FreeSpace 2 installation, e.g. by modifying or removing the retail VP files;\n"
708 "\t3) You haven't installed FreeSpace 2 at all. (Note that installing FreeSpace Open does NOT remove the need for a FreeSpace 2 installation.)\n"
709 "Number 1 can be fixed by simply moving the FreeSpace Open executable file to the FreeSpace 2 folder. Numbers 2 and 3 can be fixed by installing or reinstalling FreeSpace 2.\n");
710 }
711 }
712
713 mprintf(("GRAPHICS: Initializing default colors...\n"));
714
715 gr_set_color(0,0,0);
716 gr_set_clear_color(0, 0, 0);
717
718 gr_set_shader(NULL);
719
720 os_set_title(Osreg_title);
721
722 Gr_inited = 1;
723
724 return true;
725 }
726
gr_force_windowed()727 void gr_force_windowed()
728 {
729 if ( !Gr_inited ) {
730 return;
731 }
732
733 switch( gr_screen.mode ) {
734 case GR_OPENGL:
735 break;
736 case GR_STUB:
737 break;
738 default:
739 Int3(); // Invalid graphics mode
740 }
741
742 if ( Os_debugger_running ) {
743 Sleep(1000);
744 }
745 }
746
747 int gr_activated = 0;
gr_activate(int active)748 void gr_activate(int active)
749 {
750
751 if (gr_activated == active) {
752 return;
753 }
754 gr_activated = active;
755
756 if ( !Gr_inited ) {
757 return;
758 }
759
760 switch( gr_screen.mode ) {
761 case GR_OPENGL:
762 extern void gr_opengl_activate(int active);
763 gr_opengl_activate(active);
764 break;
765 case GR_STUB:
766 break;
767 default:
768 Int3(); // Invalid graphics mode
769 }
770
771 }
772
773 // color stuff
gr_get_color(int * r,int * g,int * b)774 void gr_get_color( int *r, int *g, int *b )
775 {
776 if (r) *r = gr_screen.current_color.red;
777 if (g) *g = gr_screen.current_color.green;
778 if (b) *b = gr_screen.current_color.blue;
779 }
780
gr_init_color(color * c,int r,int g,int b)781 void gr_init_color(color *c, int r, int g, int b)
782 {
783 CAP(r, 0, 255);
784 CAP(g, 0, 255);
785 CAP(b, 0, 255);
786
787 c->screen_sig = gr_screen.signature;
788 c->red = (ubyte)r;
789 c->green = (ubyte)g;
790 c->blue = (ubyte)b;
791 c->alpha = 255;
792 c->ac_type = AC_TYPE_NONE;
793 c->alphacolor = -1;
794 c->is_alphacolor = 0;
795 c->magic = 0xAC01;
796 c->raw8 = 0;
797 }
798
gr_init_alphacolor(color * clr,int r,int g,int b,int alpha,int type)799 void gr_init_alphacolor( color *clr, int r, int g, int b, int alpha, int type )
800 {
801 CAP(r, 0, 255);
802 CAP(g, 0, 255);
803 CAP(b, 0, 255);
804 CAP(alpha, 0, 255);
805
806 gr_init_color( clr, r, g, b );
807
808 clr->alpha = (ubyte)alpha;
809 clr->ac_type = (ubyte)type;
810 clr->alphacolor = -1;
811 clr->is_alphacolor = 1;
812 }
813
gr_set_color(int r,int g,int b)814 void gr_set_color( int r, int g, int b )
815 {
816 Assert((r >= 0) && (r < 256));
817 Assert((g >= 0) && (g < 256));
818 Assert((b >= 0) && (b < 256));
819
820 gr_init_color( &gr_screen.current_color, r, g, b );
821 }
822
gr_set_color_fast(color * dst)823 void gr_set_color_fast(color *dst)
824 {
825 if ( dst->screen_sig != gr_screen.signature ) {
826 if (dst->is_alphacolor) {
827 gr_init_alphacolor( dst, dst->red, dst->green, dst->blue, dst->alpha, dst->ac_type );
828 } else {
829 gr_init_color( dst, dst->red, dst->green, dst->blue );
830 }
831 }
832
833 gr_screen.current_color = *dst;
834 }
835
836 // shader functions
gr_create_shader(shader * shade,ubyte r,ubyte g,ubyte b,ubyte c)837 void gr_create_shader(shader *shade, ubyte r, ubyte g, ubyte b, ubyte c )
838 {
839 shade->screen_sig = gr_screen.signature;
840 shade->r = r;
841 shade->g = g;
842 shade->b = b;
843 shade->c = c;
844 }
845
gr_set_shader(shader * shade)846 void gr_set_shader(shader *shade)
847 {
848 if (shade) {
849 if (shade->screen_sig != gr_screen.signature) {
850 gr_create_shader( shade, shade->r, shade->g, shade->b, shade->c );
851 }
852 gr_screen.current_shader = *shade;
853 } else {
854 gr_create_shader( &gr_screen.current_shader, 0, 0, 0, 0 );
855 }
856 }
857
858 /**
859 * Set the bitmap for the mouse pointer. This is called by the animating mouse
860 * pointer code.
861 *
862 * The lock parameter just locks basically disables the next call of this function that doesn't
863 * have an unlock feature. If adding in more cursor-changing situations, be aware of
864 * unexpected results. You have been warned.
865 *
866 * @todo investigate memory leak of original Gr_cursor bitmap when this is called
867 */
gr_set_cursor_bitmap(int n,int lock)868 void gr_set_cursor_bitmap(int n, int lock)
869 {
870 int w, h;
871 static int locked = 0;
872
873 if ( !locked || (lock == GR_CURSOR_UNLOCK) ) {
874 // if we are changing the cursor to something different
875 // then unload the previous cursor's data - taylor
876 if ( (Gr_cursor >= 0) && (Gr_cursor != n) ) {
877 // be sure to avoid changing a cursor which is simply another frame
878 if ( (GL_cursor_nframes < 2) || ((n - Gr_cursor) >= GL_cursor_nframes) ) {
879 gr_unset_cursor_bitmap(Gr_cursor);
880 }
881 }
882
883 if (n != Gr_cursor) {
884 // get cursor size, so that we can be sure to account for the full thing
885 // in later cursor hiding code
886 bm_get_info(n, &w, &h, NULL, &GL_cursor_nframes);
887 Assert( GL_cursor_nframes > 0 );
888
889 Gr_cursor_size = MAX(w, h);
890
891 if (Gr_cursor_size <= 0) {
892 Int3();
893 Gr_cursor_size = 32;
894 }
895 }
896
897 Gr_cursor = n;
898 } else {
899 locked = 0;
900 }
901
902 if (lock == GR_CURSOR_LOCK) {
903 locked = 1;
904 }
905 }
906
gr_unset_cursor_bitmap(int n)907 void gr_unset_cursor_bitmap(int n)
908 {
909 if (n < 0) {
910 return;
911 }
912
913 if (Gr_cursor == n) {
914 bm_unload(Gr_cursor);
915 Gr_cursor = -1;
916 }
917 }
918
919 /**
920 * Retrieves the current bitmap
921 * Used in UI_GADGET to save/restore current cursor state
922 */
gr_get_cursor_bitmap()923 int gr_get_cursor_bitmap()
924 {
925 return Gr_cursor;
926 }
927
928 // new bitmap functions
gr_bitmap(int _x,int _y,int resize_mode)929 void gr_bitmap(int _x, int _y, int resize_mode)
930 {
931 int _w, _h;
932 float x, y, w, h;
933 vertex verts[4];
934
935 if (gr_screen.mode == GR_STUB) {
936 return;
937 }
938
939 bm_get_info(gr_screen.current_bitmap, &_w, &_h, NULL, NULL, NULL);
940
941 x = i2fl(_x);
942 y = i2fl(_y);
943 w = i2fl(_w);
944 h = i2fl(_h);
945
946 // I will tidy this up later - RT
947 if ( resize_mode != GR_RESIZE_NONE && (gr_screen.custom_size || (gr_screen.rendering_to_texture != -1)) ) {
948 gr_resize_screen_posf(&x, &y, &w, &h, resize_mode);
949 }
950
951 memset(verts, 0, sizeof(verts));
952
953 verts[0].screen.xyw.x = x;
954 verts[0].screen.xyw.y = y;
955 verts[0].texture_position.u = 0.0f;
956 verts[0].texture_position.v = 0.0f;
957
958 verts[1].screen.xyw.x = x + w;
959 verts[1].screen.xyw.y = y;
960 verts[1].texture_position.u = 1.0f;
961 verts[1].texture_position.v = 0.0f;
962
963 verts[2].screen.xyw.x = x + w;
964 verts[2].screen.xyw.y = y + h;
965 verts[2].texture_position.u = 1.0f;
966 verts[2].texture_position.v = 1.0f;
967
968 verts[3].screen.xyw.x = x;
969 verts[3].screen.xyw.y = y + h;
970 verts[3].texture_position.u = 0.0f;
971 verts[3].texture_position.v = 1.0f;
972
973 // turn off zbuffering
974 int saved_zbuffer_mode = gr_zbuffer_get();
975 gr_zbuffer_set(GR_ZBUFF_NONE);
976
977 gr_render(4, verts, TMAP_FLAG_TEXTURED | TMAP_FLAG_INTERFACE);
978
979 gr_zbuffer_set(saved_zbuffer_mode);
980 }
981
gr_bitmap_uv(int _x,int _y,int _w,int _h,float _u0,float _v0,float _u1,float _v1,int resize_mode)982 void gr_bitmap_uv(int _x, int _y, int _w, int _h, float _u0, float _v0, float _u1, float _v1, int resize_mode)
983 {
984 float x, y, w, h;
985 vertex verts[4];
986
987 if (gr_screen.mode == GR_STUB) {
988 return;
989 }
990
991 x = i2fl(_x);
992 y = i2fl(_y);
993 w = i2fl(_w);
994 h = i2fl(_h);
995
996 // I will tidy this up later - RT
997 if ( resize_mode != GR_RESIZE_NONE && (gr_screen.custom_size || (gr_screen.rendering_to_texture != -1)) ) {
998 gr_resize_screen_posf(&x, &y, &w, &h, resize_mode);
999 }
1000
1001 memset(verts, 0, sizeof(verts));
1002
1003 verts[0].screen.xyw.x = x;
1004 verts[0].screen.xyw.y = y;
1005 verts[0].texture_position.u = _u0;
1006 verts[0].texture_position.v = _v0;
1007
1008 verts[1].screen.xyw.x = x + w;
1009 verts[1].screen.xyw.y = y;
1010 verts[1].texture_position.u = _u1;
1011 verts[1].texture_position.v = _v0;
1012
1013 verts[2].screen.xyw.x = x + w;
1014 verts[2].screen.xyw.y = y + h;
1015 verts[2].texture_position.u = _u1;
1016 verts[2].texture_position.v = _v1;
1017
1018 verts[3].screen.xyw.x = x;
1019 verts[3].screen.xyw.y = y + h;
1020 verts[3].texture_position.u = _u0;
1021 verts[3].texture_position.v = _v1;
1022
1023 // turn off zbuffering
1024 int saved_zbuffer_mode = gr_zbuffer_get();
1025 gr_zbuffer_set(GR_ZBUFF_NONE);
1026
1027 gr_render(4, verts, TMAP_FLAG_TEXTURED | TMAP_FLAG_INTERFACE);
1028
1029 gr_zbuffer_set(saved_zbuffer_mode);
1030 }
1031
1032 // NEW new bitmap functions -Bobboau
gr_bitmap_list(bitmap_2d_list * list,int n_bm,int resize_mode)1033 void gr_bitmap_list(bitmap_2d_list* list, int n_bm, int resize_mode)
1034 {
1035 for (int i = 0; i < n_bm; i++) {
1036 bitmap_2d_list *l = &list[i];
1037
1038 bm_get_info(gr_screen.current_bitmap, &l->w, &l->h, NULL, NULL, NULL);
1039
1040 if ( resize_mode != GR_RESIZE_NONE && (gr_screen.custom_size || (gr_screen.rendering_to_texture != -1)) ) {
1041 gr_resize_screen_pos(&l->x, &l->y, &l->w, &l->h, resize_mode);
1042 }
1043 }
1044
1045 g3_draw_2d_poly_bitmap_list(list, n_bm, TMAP_FLAG_INTERFACE);
1046 }
1047
1048 // _->NEW<-_ NEW new bitmap functions -Bobboau
1049 //takes a list of rectangles that have assosiated rectangles in a texture
gr_bitmap_list(bitmap_rect_list * list,int n_bm,int resize_mode)1050 void gr_bitmap_list(bitmap_rect_list* list, int n_bm, int resize_mode)
1051 {
1052 for(int i = 0; i < n_bm; i++) {
1053 bitmap_2d_list *l = &list[i].screen_rect;
1054
1055 // if no valid hight or width values were given get some from the bitmap
1056 if ( (l->w <= 0) || (l->h <= 0) ) {
1057 bm_get_info(gr_screen.current_bitmap, &l->w, &l->h, NULL, NULL, NULL);
1058 }
1059
1060 if ( resize_mode != GR_RESIZE_NONE && (gr_screen.custom_size || (gr_screen.rendering_to_texture != -1)) ) {
1061 gr_resize_screen_pos(&l->x, &l->y, &l->w, &l->h, resize_mode);
1062 }
1063 }
1064
1065 g3_draw_2d_poly_bitmap_rect_list(list, n_bm, TMAP_FLAG_INTERFACE);
1066 }
1067
1068
1069 /**
1070 * Given endpoints, and thickness, calculate coords of the endpoint
1071 */
gr_pline_helper(vec3d * out,vec3d * in1,vec3d * in2,int thickness)1072 void gr_pline_helper(vec3d *out, vec3d *in1, vec3d *in2, int thickness)
1073 {
1074 vec3d slope;
1075
1076 // slope of the line
1077 if(vm_vec_same(in1, in2)) {
1078 slope = vmd_zero_vector;
1079 } else {
1080 vm_vec_sub(&slope, in2, in1);
1081 float temp = -slope.xyz.x;
1082 slope.xyz.x = slope.xyz.y;
1083 slope.xyz.y = temp;
1084 vm_vec_normalize(&slope);
1085 }
1086 // get the points
1087 vm_vec_scale_add(out, in1, &slope, (float)thickness);
1088 }
1089
1090 /**
1091 * Special function for drawing polylines.
1092 *
1093 * This function is specifically intended for polylines where each section
1094 * is no more than 90 degrees away from a previous section.
1095 * Moreover, it is _really_ intended for use with 45 degree angles.
1096 */
gr_pline_special(vec3d ** pts,int num_pts,int thickness,int resize_mode)1097 void gr_pline_special(vec3d **pts, int num_pts, int thickness,int resize_mode)
1098 {
1099 vec3d s1, s2, e1, e2, dir;
1100 vec3d last_e1, last_e2;
1101 vertex v[4];
1102 vertex *verts[4] = {&v[0], &v[1], &v[2], &v[3]};
1103 int saved_zbuffer_mode, idx;
1104 int started_frame = 0;
1105
1106 // if we have less than 2 pts, bail
1107 if(num_pts < 2) {
1108 return;
1109 }
1110
1111 extern int G3_count;
1112 if(G3_count == 0) {
1113 g3_start_frame(1);
1114 started_frame = 1;
1115 }
1116
1117 // turn off zbuffering
1118 saved_zbuffer_mode = gr_zbuffer_get();
1119 gr_zbuffer_set(GR_ZBUFF_NONE);
1120
1121 // turn off culling
1122 int cull = gr_set_cull(0);
1123
1124 // draw each section
1125 last_e1 = vmd_zero_vector;
1126 last_e2 = vmd_zero_vector;
1127 int j;
1128 for(idx=0; idx<num_pts-1; idx++) {
1129 // get the start and endpoints
1130 s1 = *pts[idx]; // start 1 (on the line)
1131 gr_pline_helper(&s2, pts[idx], pts[idx+1], thickness); // start 2
1132 e1 = *pts[idx+1]; // end 1 (on the line)
1133 vm_vec_sub(&dir, pts[idx+1], pts[idx]);
1134 vm_vec_add(&e2, &s2, &dir); // end 2
1135
1136 // stuff coords
1137 v[0].screen.xyw.x = (float)ceil(s1.xyz.x);
1138 v[0].screen.xyw.y = (float)ceil(s1.xyz.y);
1139 v[0].screen.xyw.w = 0.0f;
1140 v[0].texture_position.u = 0.5f;
1141 v[0].texture_position.v = 0.5f;
1142 v[0].flags = PF_PROJECTED;
1143 v[0].codes = 0;
1144 v[0].r = gr_screen.current_color.red;
1145 v[0].g = gr_screen.current_color.green;
1146 v[0].b = gr_screen.current_color.blue;
1147
1148 v[1].screen.xyw.x = (float)ceil(s2.xyz.x);
1149 v[1].screen.xyw.y = (float)ceil(s2.xyz.y);
1150 v[1].screen.xyw.w = 0.0f;
1151 v[1].texture_position.u = 0.5f;
1152 v[1].texture_position.v = 0.5f;
1153 v[1].flags = PF_PROJECTED;
1154 v[1].codes = 0;
1155 v[1].r = gr_screen.current_color.red;
1156 v[1].g = gr_screen.current_color.green;
1157 v[1].b = gr_screen.current_color.blue;
1158
1159 v[2].screen.xyw.x = (float)ceil(e2.xyz.x);
1160 v[2].screen.xyw.y = (float)ceil(e2.xyz.y);
1161 v[2].screen.xyw.w = 0.0f;
1162 v[2].texture_position.u = 0.5f;
1163 v[2].texture_position.v = 0.5f;
1164 v[2].flags = PF_PROJECTED;
1165 v[2].codes = 0;
1166 v[2].r = gr_screen.current_color.red;
1167 v[2].g = gr_screen.current_color.green;
1168 v[2].b = gr_screen.current_color.blue;
1169
1170 v[3].screen.xyw.x = (float)ceil(e1.xyz.x);
1171 v[3].screen.xyw.y = (float)ceil(e1.xyz.y);
1172 v[3].screen.xyw.w = 0.0f;
1173 v[3].texture_position.u = 0.5f;
1174 v[3].texture_position.v = 0.5f;
1175 v[3].flags = PF_PROJECTED;
1176 v[3].codes = 0;
1177 v[3].r = gr_screen.current_color.red;
1178 v[3].g = gr_screen.current_color.green;
1179 v[3].b = gr_screen.current_color.blue;
1180
1181 //We could really do this better...but oh well. _WMC
1182 if(resize_mode != GR_RESIZE_NONE) {
1183 for(j=0;j<4;j++) {
1184 gr_resize_screen_posf(&v[j].screen.xyw.x,&v[j].screen.xyw.y,NULL,NULL,resize_mode);
1185 }
1186 }
1187
1188 // draw the polys
1189 g3_draw_poly_constant_sw(4, verts, TMAP_FLAG_GOURAUD | TMAP_FLAG_RGB, 0.1f);
1190
1191 // if we're past the first section, draw a "patch" triangle to fill any gaps
1192 if(idx > 0) {
1193 // stuff coords
1194 v[0].screen.xyw.x = (float)ceil(s1.xyz.x);
1195 v[0].screen.xyw.y = (float)ceil(s1.xyz.y);
1196 v[0].screen.xyw.w = 0.0f;
1197 v[0].texture_position.u = 0.5f;
1198 v[0].texture_position.v = 0.5f;
1199 v[0].flags = PF_PROJECTED;
1200 v[0].codes = 0;
1201 v[0].r = gr_screen.current_color.red;
1202 v[0].g = gr_screen.current_color.green;
1203 v[0].b = gr_screen.current_color.blue;
1204
1205 v[1].screen.xyw.x = (float)ceil(s2.xyz.x);
1206 v[1].screen.xyw.y = (float)ceil(s2.xyz.y);
1207 v[1].screen.xyw.w = 0.0f;
1208 v[1].texture_position.u = 0.5f;
1209 v[1].texture_position.v = 0.5f;
1210 v[1].flags = PF_PROJECTED;
1211 v[1].codes = 0;
1212 v[1].r = gr_screen.current_color.red;
1213 v[1].g = gr_screen.current_color.green;
1214 v[1].b = gr_screen.current_color.blue;
1215
1216
1217 v[2].screen.xyw.x = (float)ceil(last_e2.xyz.x);
1218 v[2].screen.xyw.y = (float)ceil(last_e2.xyz.y);
1219 v[2].screen.xyw.w = 0.0f;
1220 v[2].texture_position.u = 0.5f;
1221 v[2].texture_position.v = 0.5f;
1222 v[2].flags = PF_PROJECTED;
1223 v[2].codes = 0;
1224 v[2].r = gr_screen.current_color.red;
1225 v[2].g = gr_screen.current_color.green;
1226 v[2].b = gr_screen.current_color.blue;
1227
1228 //Inefficiency or flexibility? you be the judge -WMC
1229 if(resize_mode != GR_RESIZE_NONE) {
1230 for(j=0;j<3;j++) {
1231 gr_resize_screen_posf(&v[j].screen.xyw.x,&v[j].screen.xyw.y,NULL,NULL,resize_mode);
1232 }
1233 }
1234
1235 g3_draw_poly_constant_sw(3, verts, TMAP_FLAG_GOURAUD | TMAP_FLAG_RGB, 0.1f);
1236 }
1237
1238 // store our endpoints
1239 last_e1 = e1;
1240 last_e2 = e2;
1241 }
1242
1243 if(started_frame) {
1244 g3_end_frame();
1245 }
1246
1247 // restore zbuffer mode
1248 gr_zbuffer_set(saved_zbuffer_mode);
1249
1250 // restore culling
1251 gr_set_cull(cull);
1252 }
1253
find_first_vertex(int idx)1254 int poly_list::find_first_vertex(int idx)
1255 {
1256 vec3d *o_norm = &norm[idx];
1257 vertex *o_vert = &vert[idx];
1258 vec3d *p_norm = &norm[0];
1259 vertex *p_vert = &vert[0];
1260
1261 // we should always equal ourselves, so just use that as the stopping point
1262 for (int i = 0; i < idx; i++) {
1263 if ( (*p_norm == *o_norm)
1264 && (p_vert->world == o_vert->world)
1265 && (p_vert->texture_position == o_vert->texture_position) )
1266 {
1267 return i;
1268 }
1269
1270 ++p_norm;
1271 ++p_vert;
1272 }
1273
1274 return idx;
1275 }
1276
1277 /**
1278 * Given a list (plist) find the index within the indexed list that the vert at position idx within list is at
1279 */
find_index(poly_list * plist,int idx)1280 int poly_list::find_index(poly_list *plist, int idx)
1281 {
1282 vec3d *o_norm = &plist->norm[idx];
1283 vertex *o_vert = &plist->vert[idx];
1284 vec3d *p_norm = &norm[0];
1285 vertex *p_vert = &vert[0];
1286
1287 for (int i = 0; i < n_verts; i++) {
1288 if ( (*p_norm == *o_norm)
1289 && (p_vert->world == o_vert->world)
1290 && (p_vert->texture_position == o_vert->texture_position))
1291 {
1292 return i;
1293 }
1294
1295 ++p_vert;
1296 ++p_norm;
1297 }
1298
1299 return -1;
1300 }
1301
1302
allocate(int _verts)1303 void poly_list::allocate(int _verts)
1304 {
1305 if (_verts <= currently_allocated)
1306 return;
1307
1308 if (vert != NULL) {
1309 vm_free(vert);
1310 vert = NULL;
1311 }
1312
1313 if (norm != NULL) {
1314 vm_free(norm);
1315 norm = NULL;
1316 }
1317
1318 if (tsb != NULL) {
1319 vm_free(tsb);
1320 tsb = NULL;
1321 }
1322
1323 if (_verts) {
1324 vert = (vertex*)vm_malloc(sizeof(vertex) * _verts);
1325 norm = (vec3d*)vm_malloc(sizeof(vec3d) * _verts);
1326
1327 if (Cmdline_normal) {
1328 tsb = (tsb_t*)vm_malloc(sizeof(tsb_t) * _verts);
1329 }
1330 }
1331
1332 n_verts = 0;
1333 currently_allocated = _verts;
1334 }
1335
~poly_list()1336 poly_list::~poly_list()
1337 {
1338 if (vert != NULL) {
1339 vm_free(vert);
1340 vert = NULL;
1341 }
1342
1343 if (norm != NULL) {
1344 vm_free(norm);
1345 norm = NULL;
1346 }
1347
1348 if (tsb != NULL) {
1349 vm_free(tsb);
1350 tsb = NULL;
1351 }
1352 }
1353
calculate_tangent()1354 void poly_list::calculate_tangent()
1355 {
1356 vertex *v0, *v1, *v2;
1357 vec3d *t0, *t1, *t2;
1358 vec3d side0, side1;
1359 vec3d vt0, vt1;
1360 float deltaU0, deltaV0, deltaU1, deltaV1;
1361 vec3d tangent, binormal, cross;
1362 float magg, scale;
1363
1364 if ( !Cmdline_normal ) {
1365 return;
1366 }
1367
1368 Assert( !(n_verts % 3) );
1369
1370 for (int i = 0; i < n_verts; i += 3) {
1371 // vertex (reading)
1372 v0 = &vert[i];
1373 v1 = &vert[i+1];
1374 v2 = &vert[i+2];
1375 // tangents (writing)
1376 t0 = &tsb[i].tangent;
1377 t1 = &tsb[i+1].tangent;
1378 t2 = &tsb[i+2].tangent;
1379
1380
1381 deltaU0 = v1->texture_position.u - v0->texture_position.u;
1382 deltaV0 = v1->texture_position.v - v0->texture_position.v;
1383
1384 deltaU1 = v2->texture_position.u - v0->texture_position.u;
1385 deltaV1 = v2->texture_position.v - v0->texture_position.v;
1386
1387 // quick short circuit for NULL case
1388 float n = (deltaU0 * deltaV1) - (deltaU1 * deltaV0);
1389
1390 if (n == 0.0f) {
1391 // hit NULL, so just set identity
1392 tangent = vmd_x_vector;
1393 binormal = vmd_y_vector;
1394 } else {
1395 float blah = 1.0f / n;
1396
1397 vm_vec_sub(&side0, &v1->world, &v0->world);
1398 vm_vec_sub(&side1, &v2->world, &v0->world);
1399
1400 // tangent
1401 vm_vec_copy_scale(&vt0, &side0, deltaV1);
1402 vm_vec_copy_scale(&vt1, &side1, deltaV0);
1403 vm_vec_sub(&tangent, &vt0, &vt1);
1404 vm_vec_scale(&tangent, blah);
1405
1406 // binormal
1407 vm_vec_copy_scale(&vt0, &side0, deltaU1);
1408 vm_vec_copy_scale(&vt1, &side1, deltaU0);
1409 vm_vec_sub(&binormal, &vt0, &vt1);
1410 vm_vec_scale(&binormal, blah);
1411 }
1412
1413 // orthogonalize tangent (for all 3 verts)
1414 magg = vm_vec_dot(&norm[i], &tangent);
1415 vm_vec_scale_sub(t0, &tangent, &norm[i], magg);
1416 vm_vec_normalize_safe(t0);
1417
1418 magg = vm_vec_dot(&norm[i+1], &tangent);
1419 vm_vec_scale_sub(t1, &tangent, &norm[i+1], magg);
1420 vm_vec_normalize_safe(t1);
1421
1422 magg = vm_vec_dot(&norm[i+2], &tangent);
1423 vm_vec_scale_sub(t2, &tangent, &norm[i+2], magg);
1424 vm_vec_normalize_safe(t2);
1425
1426 // compute handedness (for all 3 verts)
1427 vm_vec_crossprod(&cross, &norm[i], &tangent);
1428 scale = vm_vec_dot(&cross, &binormal);
1429 tsb[i].scaler = (scale < 0.0f) ? -1.0f : 1.0f;
1430
1431 vm_vec_crossprod(&cross, &norm[i+1], &tangent);
1432 scale = vm_vec_dot(&cross, &binormal);
1433 tsb[i+1].scaler = (scale < 0.0f) ? -1.0f : 1.0f;
1434
1435 vm_vec_crossprod(&cross, &norm[i+2], &tangent);
1436 scale = vm_vec_dot(&cross, &binormal);
1437 tsb[i+2].scaler = (scale < 0.0f) ? -1.0f : 1.0f;
1438 }
1439 }
1440
1441 static poly_list buffer_list_internal;
1442
make_index_buffer(SCP_vector<int> & vertex_list)1443 void poly_list::make_index_buffer(SCP_vector<int> &vertex_list)
1444 {
1445 int nverts = 0;
1446 int j, z = 0;
1447 ubyte *nverts_good = NULL;
1448
1449 // calculate tangent space data (must be done early)
1450 calculate_tangent();
1451
1452 // using vm_malloc() here rather than 'new' so we get the extra out-of-memory check
1453 nverts_good = (ubyte *) vm_malloc(n_verts);
1454
1455 Assert( nverts_good != NULL );
1456 if ( nverts_good == NULL )
1457 return;
1458
1459 memset( nverts_good, 0, n_verts );
1460
1461 vertex_list.reserve(n_verts);
1462
1463 for (j = 0; j < n_verts; j++) {
1464 if (find_first_vertex(j) == j) {
1465 nverts++;
1466 nverts_good[j] = 1;
1467 vertex_list.push_back(j);
1468 }
1469 }
1470
1471 // if there is nothig to change then bail
1472 if (n_verts == nverts) {
1473 if (nverts_good != NULL) {
1474 vm_free(nverts_good);
1475 }
1476
1477 return;
1478 }
1479
1480 buffer_list_internal.n_verts = 0;
1481 buffer_list_internal.allocate(nverts);
1482
1483 for (j = 0; j < n_verts; j++) {
1484 if ( !nverts_good[j] ) {
1485 continue;
1486 }
1487
1488 buffer_list_internal.vert[z] = vert[j];
1489 buffer_list_internal.norm[z] = norm[j];
1490
1491 if (Cmdline_normal) {
1492 buffer_list_internal.tsb[z] = tsb[j];
1493 }
1494
1495 buffer_list_internal.n_verts++;
1496 z++;
1497 }
1498
1499 Assert(nverts == buffer_list_internal.n_verts);
1500
1501 if (nverts_good != NULL) {
1502 vm_free(nverts_good);
1503 }
1504
1505 (*this) = buffer_list_internal;
1506 }
1507
operator =(poly_list & other_list)1508 poly_list& poly_list::operator = (poly_list &other_list)
1509 {
1510 allocate(other_list.n_verts);
1511
1512 memcpy(norm, other_list.norm, sizeof(vec3d) * other_list.n_verts);
1513 memcpy(vert, other_list.vert, sizeof(vertex) * other_list.n_verts);
1514
1515 if (Cmdline_normal) {
1516 memcpy(tsb, other_list.tsb, sizeof(tsb_t) * other_list.n_verts);
1517 }
1518
1519 n_verts = other_list.n_verts;
1520
1521 return *this;
1522 }
1523
gr_shield_icon(coord2d coords[6],int resize_mode)1524 void gr_shield_icon(coord2d coords[6], int resize_mode)
1525 {
1526 if (gr_screen.mode == GR_STUB) {
1527 return;
1528 }
1529
1530 if (resize_mode != GR_RESIZE_NONE) {
1531 gr_resize_screen_pos(&coords[0].x, &coords[0].y, NULL, NULL, resize_mode);
1532 gr_resize_screen_pos(&coords[1].x, &coords[1].y, NULL, NULL, resize_mode);
1533 gr_resize_screen_pos(&coords[2].x, &coords[2].y, NULL, NULL, resize_mode);
1534 gr_resize_screen_pos(&coords[3].x, &coords[3].y, NULL, NULL, resize_mode);
1535 gr_resize_screen_pos(&coords[4].x, &coords[4].y, NULL, NULL, resize_mode);
1536 gr_resize_screen_pos(&coords[5].x, &coords[5].y, NULL, NULL, resize_mode);
1537 }
1538
1539 g3_draw_2d_shield_icon(coords,
1540 gr_screen.current_color.red,
1541 gr_screen.current_color.green,
1542 gr_screen.current_color.blue,
1543 gr_screen.current_color.alpha);
1544 }
1545
gr_rect(int x,int y,int w,int h,int resize_mode)1546 void gr_rect(int x, int y, int w, int h, int resize_mode)
1547 {
1548 if (gr_screen.mode == GR_STUB) {
1549 return;
1550 }
1551
1552 if (resize_mode != GR_RESIZE_NONE) {
1553 gr_resize_screen_pos(&x, &y, &w, &h, resize_mode);
1554 }
1555
1556 g3_draw_2d_rect(x, y, w, h,
1557 gr_screen.current_color.red,
1558 gr_screen.current_color.green,
1559 gr_screen.current_color.blue,
1560 gr_screen.current_color.alpha);
1561 }
1562
gr_shade(int x,int y,int w,int h,int resize_mode)1563 void gr_shade(int x, int y, int w, int h, int resize_mode)
1564 {
1565 int r, g, b, a;
1566
1567 if (gr_screen.mode == GR_STUB) {
1568 return;
1569 }
1570
1571 if (resize_mode != GR_RESIZE_NONE) {
1572 gr_resize_screen_pos(&x, &y, &w, &h, resize_mode);
1573 }
1574
1575 r = (int)gr_screen.current_shader.r;
1576 g = (int)gr_screen.current_shader.g;
1577 b = (int)gr_screen.current_shader.b;
1578 a = (int)gr_screen.current_shader.c;
1579
1580 g3_draw_2d_rect(x, y, w, h, r, g, b, a);
1581 }
1582
gr_set_bitmap(int bitmap_num,int alphablend_mode,int bitblt_mode,float alpha)1583 void gr_set_bitmap(int bitmap_num, int alphablend_mode, int bitblt_mode, float alpha)
1584 {
1585 gr_screen.current_alpha = alpha;
1586 gr_screen.current_alphablend_mode = alphablend_mode;
1587 gr_screen.current_bitblt_mode = bitblt_mode;
1588 gr_screen.current_bitmap = bitmap_num;
1589 }
1590
gr_flip()1591 void gr_flip()
1592 {
1593 // m!m avoid running CHA_ONFRAME when the "Quit mission" popup is shown. See mantis 2446 for reference
1594 if (!quit_mission_popup_shown)
1595 {
1596 //WMC - Evaluate global hook if not override.
1597 Script_system.RunBytecode(Script_globalhook);
1598 //WMC - Do conditional hooks. Yippee!
1599 Script_system.RunCondition(CHA_ONFRAME);
1600 //WMC - Do scripting reset stuff
1601 Script_system.EndFrame();
1602 }
1603
1604 gr_screen.gf_flip();
1605 }
1606