This commit was manufactured by cvs2svn to create branch 'pinder'.
[newkind] / alg_gfx.c
1 /**
2 *
3 * Elite - The New Kind.
4 *
5 * Allegro version of Graphics routines.
6 *
7 * The code in this file has not been derived from the original Elite code.
8 * Written by C.J.Pinder 1999-2001.
9 * email: <christian@newkind.co.uk>
10 *
11 * Routines for drawing anti-aliased lines and circles by T.Harte.
12 *
13 **/
14
15 #include <string.h>
16 #include <stdlib.h>
17 #include <stdio.h>
18 #include <math.h>
19 #include <ctype.h>
20
21 #include "allegro.h"
22
23 #include "config.h"
24 #include "gfx.h"
25 #include "alg_data.h"
26 #include "elite.h"
27
28 BITMAP *gfx_screen;
29 volatile int frame_count;
30 DATAFILE *datafile;
31 BITMAP *scanner_image;
32
33 #define MAX_POLYS 100
34
35 static int start_poly;
36 static int total_polys;
37
38 struct poly_data
39 {
40 int z;
41 int no_points;
42 int face_colour;
43 int point_list[16];
44 int next;
45 };
46
47 static struct poly_data poly_chain[MAX_POLYS];
48
49
50
51
52 void frame_timer (void)
53 {
54 frame_count++;
55 }
56 END_OF_FUNCTION(frame_timer);
57
58
59
60 int gfx_graphics_startup (void)
61 {
62 PALETTE the_palette;
63 int rv;
64
65 #ifdef ALLEGRO_WINDOWS
66
67 #ifdef RES_512_512
68 rv = set_gfx_mode(GFX_DIRECTX_OVL, 512, 512, 0, 0);
69
70 if (rv != 0)
71 rv = set_gfx_mode(GFX_DIRECTX_WIN, 512, 512, 0, 0);
72
73 if (rv != 0)
74 rv = set_gfx_mode(GFX_GDI, 512, 512, 0, 0);
75
76 if (rv == 0)
77 set_display_switch_mode (SWITCH_BACKGROUND);
78 #else
79 rv = set_gfx_mode(GFX_DIRECTX, 800, 600, 0, 0);
80
81 if (rv != 0)
82 rv = set_gfx_mode(GFX_GDI, 800, 600, 0, 0);
83 #endif
84
85 #else
86 rv = set_gfx_mode(GFX_AUTODETECT, 800, 600, 0, 0);
87 #endif
88
89 if (rv != 0)
90 {
91 set_gfx_mode(GFX_TEXT, 0, 0, 0, 0);
92 allegro_message("Unable to set graphics mode.");
93 return 1;
94 }
95
96 datafile = load_datafile("elite.dat");
97 if (!datafile)
98 {
99 set_gfx_mode(GFX_TEXT, 0, 0, 0, 0);
100 allegro_message("Error loading %s!\n", "elite.dat");
101 return 1;
102 }
103
104 scanner_image = load_bitmap(scanner_filename, the_palette);
105 if (!scanner_image)
106 {
107 set_gfx_mode(GFX_TEXT, 0, 0, 0, 0);
108 allegro_message("Error reading scanner bitmap file.\n");
109 return 1;
110 }
111
112 /* select the scanner palette */
113 set_palette(the_palette);
114
115 /* Create the screen buffer bitmap */
116 gfx_screen = create_bitmap (SCREEN_W, SCREEN_H);
117
118 clear (gfx_screen);
119
120 blit (scanner_image, gfx_screen, 0, 0, GFX_X_OFFSET, 385+GFX_Y_OFFSET, scanner_image->w, scanner_image->h);
121 gfx_draw_line (0, 0, 0, 384);
122 gfx_draw_line (0, 0, 511, 0);
123 gfx_draw_line (511, 0, 511, 384);
124
125 /* Install a timer to regulate the speed of the game... */
126
127 LOCK_VARIABLE(frame_count);
128 LOCK_FUNCTION(frame_timer);
129 frame_count = 0;
130 install_int (frame_timer, speed_cap);
131
132 return 0;
133 }
134
135
136 void gfx_graphics_shutdown (void)
137 {
138 destroy_bitmap(scanner_image);
139 destroy_bitmap(gfx_screen);
140 unload_datafile(datafile);
141 }
142
143
144 /*
145 * Blit the back buffer to the screen.
146 */
147
148 void gfx_update_screen (void)
149 {
150 while (frame_count < 1)
151 rest (10);
152 frame_count = 0;
153
154 acquire_screen();
155 blit (gfx_screen, screen, GFX_X_OFFSET, GFX_Y_OFFSET, GFX_X_OFFSET, GFX_Y_OFFSET, 512, 512);
156 release_screen();
157 }
158
159
160 void gfx_acquire_screen (void)
161 {
162 acquire_bitmap (gfx_screen);
163 }
164
165
166 void gfx_release_screen (void)
167 {
168 release_bitmap(gfx_screen);
169 }
170
171 void gfx_fast_plot_pixel (int x, int y, int col)
172 {
173 // _putpixel(gfx_screen, x, y, col);
174 gfx_screen->line[y][x] = col;
175 }
176
177
178 void gfx_plot_pixel (int x, int y, int col)
179 {
180 putpixel (gfx_screen, x + GFX_X_OFFSET, y + GFX_Y_OFFSET, col);
181 }
182
183
184 void gfx_draw_filled_circle (int cx, int cy, int radius, int circle_colour)
185 {
186 circlefill (gfx_screen, cx + GFX_X_OFFSET, cy + GFX_Y_OFFSET, radius, circle_colour);
187 }
188
189
190 #define AA_BITS 3
191 #define AA_AND 7
192 #define AA_BASE 235
193
194 #define trunc(x) ((x) & ~65535)
195 #define frac(x) ((x) & 65535)
196 #define invfrac(x) (65535-frac(x))
197 #define plot(x,y,c) putpixel(gfx_screen, (x), (y), (c)+AA_BASE)
198
199 /*
200 * Draw anti-aliased wireframe circle.
201 * By T.Harte.
202 */
203
204 void gfx_draw_aa_circle(int cx, int cy, int radius)
205 {
206 int x,y;
207 int s;
208 int sx, sy;
209
210 cx += GFX_X_OFFSET;
211 cy += GFX_Y_OFFSET;
212
213 radius >>= (16 - AA_BITS);
214
215 x = radius;
216 s = -radius;
217 y = 0;
218
219 while (y <= x)
220 {
221 //wide pixels
222 sx = cx + (x >> AA_BITS); sy = cy + (y >> AA_BITS);
223
224 plot(sx, sy, AA_AND - (x&AA_AND));
225 plot(sx + 1, sy, x&AA_AND);
226
227 sy = cy - (y >> AA_BITS);
228
229 plot(sx, sy, AA_AND - (x&AA_AND));
230 plot(sx + 1, sy, x&AA_AND);
231
232 sx = cx - (x >> AA_BITS);
233
234 plot(sx, sy, AA_AND - (x&AA_AND));
235 plot(sx - 1, sy, x&AA_AND);
236
237 sy = cy + (y >> AA_BITS);
238
239 plot(sx, sy, AA_AND - (x&AA_AND));
240 plot(sx - 1, sy, x&AA_AND);
241
242 //tall pixels
243 sx = cx + (y >> AA_BITS); sy = cy + (x >> AA_BITS);
244
245 plot(sx, sy, AA_AND - (x&AA_AND));
246 plot(sx, sy + 1, x&AA_AND);
247
248 sy = cy - (x >> AA_BITS);
249
250 plot(sx, sy, AA_AND - (x&AA_AND));
251 plot(sx, sy - 1, x&AA_AND);
252
253 sx = cx - (y >> AA_BITS);
254
255 plot(sx, sy, AA_AND - (x&AA_AND));
256 plot(sx, sy - 1, x&AA_AND);
257
258 sy = cy + (x >> AA_BITS);
259
260 plot(sx, sy, AA_AND - (x&AA_AND));
261 plot(sx, sy + 1, x&AA_AND);
262
263 s += AA_AND+1 + (y << (AA_BITS+1)) + ((1 << (AA_BITS+2))-2);
264 y += AA_AND+1;
265
266 while(s >= 0)
267 {
268 s -= (x << 1) + 2;
269 x --;
270 }
271 }
272 }
273
274
275 /*
276 * Draw anti-aliased line.
277 * By T.Harte.
278 */
279
280 void gfx_draw_aa_line (int x1, int y1, int x2, int y2)
281 {
282 fixed grad, xd, yd;
283 fixed xgap, ygap, xend, yend, xf, yf;
284 fixed brightness1, brightness2, swap;
285
286 int x, y, ix1, ix2, iy1, iy2;
287
288 x1 += itofix(GFX_X_OFFSET);
289 x2 += itofix(GFX_X_OFFSET);
290 y1 += itofix(GFX_Y_OFFSET);
291 y2 += itofix(GFX_Y_OFFSET);
292
293 xd = x2 - x1;
294 yd = y2 - y1;
295
296 if (abs(xd) > abs(yd))
297 {
298 if(x1 > x2)
299 {
300 swap = x1; x1 = x2; x2 = swap;
301 swap = y1; y1 = y2; y2 = swap;
302 xd = -xd;
303 yd = -yd;
304 }
305
306 grad = fdiv(yd, xd);
307
308 //end point 1
309
310 xend = trunc(x1 + 32768);
311 yend = y1 + fmul(grad, xend-x1);
312
313 xgap = invfrac(x1+32768);
314
315 ix1 = xend >> 16;
316 iy1 = yend >> 16;
317
318 brightness1 = fmul(invfrac(yend), xgap);
319 brightness2 = fmul(frac(yend), xgap);
320
321 plot(ix1, iy1, brightness1 >> (16-AA_BITS));
322 plot(ix1, iy1+1, brightness2 >> (16-AA_BITS));
323
324 yf = yend+grad;
325
326 //end point 2;
327
328 xend = trunc(x2 + 32768);
329 yend = y2 + fmul(grad, xend-x2);
330
331 xgap = invfrac(x2 - 32768);
332
333 ix2 = xend >> 16;
334 iy2 = yend >> 16;
335
336 brightness1 = fmul(invfrac(yend), xgap);
337 brightness2 = fmul(frac(yend), xgap);
338
339 plot(ix2, iy2, brightness1 >> (16-AA_BITS));
340 plot(ix2, iy2+1, brightness2 >> (16-AA_BITS));
341
342 for(x = ix1+1; x <= ix2-1; x++)
343 {
344 brightness1 = invfrac(yf);
345 brightness2 = frac(yf);
346
347 plot(x, (yf >> 16), brightness1 >> (16-AA_BITS));
348 plot(x, 1+(yf >> 16), brightness2 >> (16-AA_BITS));
349
350 yf += grad;
351 }
352 }
353 else
354 {
355 if(y1 > y2)
356 {
357 swap = x1; x1 = x2; x2 = swap;
358 swap = y1; y1 = y2; y2 = swap;
359 xd = -xd;
360 yd = -yd;
361 }
362
363 grad = fdiv(xd, yd);
364
365 //end point 1
366
367 yend = trunc(y1 + 32768);
368 xend = x1 + fmul(grad, yend-y1);
369
370 ygap = invfrac(y1+32768);
371
372 iy1 = yend >> 16;
373 ix1 = xend >> 16;
374
375 brightness1 = fmul(invfrac(xend), ygap);
376 brightness2 = fmul(frac(xend), ygap);
377
378 plot(ix1, iy1, brightness1 >> (16-AA_BITS));
379 plot(ix1+1, iy1, brightness2 >> (16-AA_BITS));
380
381 xf = xend+grad;
382
383 //end point 2;
384
385 yend = trunc(y2 + 32768);
386 xend = x2 + fmul(grad, yend-y2);
387
388 ygap = invfrac(y2 - 32768);
389
390 ix2 = xend >> 16;
391 iy2 = yend >> 16;
392
393 brightness1 = fmul(invfrac(xend), ygap);
394 brightness2 = fmul(frac(xend), ygap);
395
396 plot(ix2, iy2, brightness1 >> (16-AA_BITS));
397 plot(ix2+1, iy2, brightness2 >> (16-AA_BITS));
398
399 for(y = iy1+1; y <= iy2-1; y++)
400 {
401 brightness1 = invfrac(xf);
402 brightness2 = frac(xf);
403
404 plot((xf >> 16), y, brightness1 >> (16-AA_BITS));
405 plot(1+(xf >> 16), y, brightness2 >> (16-AA_BITS));
406
407 xf += grad;
408 }
409 }
410 }
411
412 #undef trunc
413 #undef frac
414 #undef invfrac
415 #undef plot
416
417 #undef AA_BITS
418 #undef AA_AND
419 #undef AA_BASE
420
421
422
423 void gfx_draw_circle (int cx, int cy, int radius, int circle_colour)
424 {
425 if (anti_alias_gfx && (circle_colour == GFX_COL_WHITE))
426 gfx_draw_aa_circle (cx, cy, itofix(radius));
427 else
428 circle (gfx_screen, cx + GFX_X_OFFSET, cy + GFX_Y_OFFSET, radius, circle_colour);
429 }
430
431
432
433 void gfx_draw_line (int x1, int y1, int x2, int y2)
434 {
435 if (y1 == y2)
436 {
437 hline (gfx_screen, x1 + GFX_X_OFFSET, y1 + GFX_Y_OFFSET, x2 + GFX_X_OFFSET, GFX_COL_WHITE);
438 return;
439 }
440
441 if (x1 == x2)
442 {
443 vline (gfx_screen, x1 + GFX_X_OFFSET, y1 + GFX_Y_OFFSET, y2 + GFX_Y_OFFSET, GFX_COL_WHITE);
444 return;
445 }
446
447 if (anti_alias_gfx)
448 gfx_draw_aa_line (itofix(x1), itofix(y1), itofix(x2), itofix(y2));
449 else
450 line (gfx_screen, x1 + GFX_X_OFFSET, y1 + GFX_Y_OFFSET, x2 + GFX_X_OFFSET, y2 + GFX_Y_OFFSET, GFX_COL_WHITE);
451 }
452
453
454
455 void gfx_draw_colour_line (int x1, int y1, int x2, int y2, int line_colour)
456 {
457 if (y1 == y2)
458 {
459 hline (gfx_screen, x1 + GFX_X_OFFSET, y1 + GFX_Y_OFFSET, x2 + GFX_X_OFFSET, line_colour);
460 return;
461 }
462
463 if (x1 == x2)
464 {
465 vline (gfx_screen, x1 + GFX_X_OFFSET, y1 + GFX_Y_OFFSET, y2 + GFX_Y_OFFSET, line_colour);
466 return;
467 }
468
469 if (anti_alias_gfx && (line_colour == GFX_COL_WHITE))
470 gfx_draw_aa_line (itofix(x1), itofix(y1), itofix(x2), itofix(y2));
471 else
472 line (gfx_screen, x1 + GFX_X_OFFSET, y1 + GFX_Y_OFFSET, x2 + GFX_X_OFFSET, y2 + GFX_Y_OFFSET, line_colour);
473 }
474
475
476
477 void gfx_draw_triangle (int x1, int y1, int x2, int y2, int x3, int y3, int col)
478 {
479 triangle (gfx_screen, x1 + GFX_X_OFFSET, y1 + GFX_Y_OFFSET, x2 + GFX_X_OFFSET, y2 + GFX_Y_OFFSET,
480 x3 + GFX_X_OFFSET, y3 + GFX_Y_OFFSET, col);
481 }
482
483
484
485 void gfx_display_text (int x, int y, char *txt)
486 {
487 text_mode (-1);
488 textout (gfx_screen, datafile[ELITE_1].dat, txt, (x / (2 / GFX_SCALE)) + GFX_X_OFFSET, (y / (2 / GFX_SCALE)) + GFX_Y_OFFSET, GFX_COL_WHITE);
489 }
490
491
492 void gfx_display_colour_text (int x, int y, char *txt, int col)
493 {
494 text_mode (-1);
495 textout (gfx_screen, datafile[ELITE_1].dat, txt, (x / (2 / GFX_SCALE)) + GFX_X_OFFSET, (y / (2 / GFX_SCALE)) + GFX_Y_OFFSET, col);
496 }
497
498
499
500 void gfx_display_centre_text (int y, char *str, int psize, int col)
501 {
502 int txt_size;
503 int txt_colour;
504
505 if (psize == 140)
506 {
507 txt_size = ELITE_2;
508 txt_colour = -1;
509 }
510 else
511 {
512 txt_size = ELITE_1;
513 txt_colour = col;
514 }
515
516 text_mode (-1);
517 textout_centre (gfx_screen, datafile[txt_size].dat, str, (128 * GFX_SCALE) + GFX_X_OFFSET, (y / (2 / GFX_SCALE)) + GFX_Y_OFFSET, txt_colour);
518 }
519
520
521 void gfx_clear_display (void)
522 {
523 rectfill (gfx_screen, GFX_X_OFFSET + 1, GFX_Y_OFFSET + 1, 510 + GFX_X_OFFSET, 383 + GFX_Y_OFFSET, GFX_COL_BLACK);
524 }
525
526 void gfx_clear_text_area (void)
527 {
528 rectfill (gfx_screen, GFX_X_OFFSET + 1, GFX_Y_OFFSET + 340, 510 + GFX_X_OFFSET, 383 + GFX_Y_OFFSET, GFX_COL_BLACK);
529 }
530
531
532 void gfx_clear_area (int tx, int ty, int bx, int by)
533 {
534 rectfill (gfx_screen, tx + GFX_X_OFFSET, ty + GFX_Y_OFFSET,
535 bx + GFX_X_OFFSET, by + GFX_Y_OFFSET, GFX_COL_BLACK);
536 }
537
538 void gfx_draw_rectangle (int tx, int ty, int bx, int by, int col)
539 {
540 rectfill (gfx_screen, tx + GFX_X_OFFSET, ty + GFX_Y_OFFSET,
541 bx + GFX_X_OFFSET, by + GFX_Y_OFFSET, col);
542 }
543
544
545 void gfx_display_pretty_text (int tx, int ty, int bx, int by, char *txt)
546 {
547 char strbuf[100];
548 char *str;
549 char *bptr;
550 int len;
551 int pos;
552 int maxlen;
553
554 maxlen = (bx - tx) / 8;
555
556 str = txt;
557 len = strlen(txt);
558
559 while (len > 0)
560 {
561 pos = maxlen;
562 if (pos > len)
563 pos = len;
564
565 while ((str[pos] != ' ') && (str[pos] != ',') &&
566 (str[pos] != '.') && (str[pos] != '\0'))
567 {
568 pos--;
569 }
570
571 len = len - pos - 1;
572
573 for (bptr = strbuf; pos >= 0; pos--)
574 *bptr++ = *str++;
575
576 *bptr = '\0';
577
578 text_mode (-1);
579 textout (gfx_screen, datafile[ELITE_1].dat, strbuf, tx + GFX_X_OFFSET, ty + GFX_Y_OFFSET, GFX_COL_WHITE);
580 ty += (8 * GFX_SCALE);
581 }
582 }
583
584
585 void gfx_draw_scanner (void)
586 {
587 blit (scanner_image, gfx_screen, 0, 0, GFX_X_OFFSET, 385+GFX_Y_OFFSET, scanner_image->w, scanner_image->h);
588 }
589
590 void gfx_set_clip_region (int tx, int ty, int bx, int by)
591 {
592 set_clip (gfx_screen, tx + GFX_X_OFFSET, ty + GFX_Y_OFFSET, bx + GFX_X_OFFSET, by + GFX_Y_OFFSET);
593 }
594
595
596 void gfx_start_render (void)
597 {
598 start_poly = 0;
599 total_polys = 0;
600 }
601
602
603 void gfx_render_polygon (int num_points, int *point_list, int face_colour, int zavg)
604 {
605 int i;
606 int x;
607 int nx;
608
609 if (total_polys == MAX_POLYS)
610 return;
611
612 x = total_polys;
613 total_polys++;
614
615 poly_chain[x].no_points = num_points;
616 poly_chain[x].face_colour = face_colour;
617 poly_chain[x].z = zavg;
618 poly_chain[x].next = -1;
619
620 for (i = 0; i < 16; i++)
621 poly_chain[x].point_list[i] = point_list[i];
622
623 if (x == 0)
624 return;
625
626 if (zavg > poly_chain[start_poly].z)
627 {
628 poly_chain[x].next = start_poly;
629 start_poly = x;
630 return;
631 }
632
633 for (i = start_poly; poly_chain[i].next != -1; i = poly_chain[i].next)
634 {
635 nx = poly_chain[i].next;
636
637 if (zavg > poly_chain[nx].z)
638 {
639 poly_chain[i].next = x;
640 poly_chain[x].next = nx;
641 return;
642 }
643 }
644
645 poly_chain[i].next = x;
646 }
647
648
649 void gfx_render_line (int x1, int y1, int x2, int y2, int dist, int col)
650 {
651 int point_list[4];
652
653 point_list[0] = x1;
654 point_list[1] = y1;
655 point_list[2] = x2;
656 point_list[3] = y2;
657
658 gfx_render_polygon (2, point_list, col, dist);
659 }
660
661
662 void gfx_finish_render (void)
663 {
664 int num_points;
665 int *pl;
666 int i;
667 int col;
668
669 if (total_polys == 0)
670 return;
671
672 for (i = start_poly; i != -1; i = poly_chain[i].next)
673 {
674 num_points = poly_chain[i].no_points;
675 pl = poly_chain[i].point_list;
676 col = poly_chain[i].face_colour;
677
678 if (num_points == 2)
679 {
680 gfx_draw_colour_line (pl[0], pl[1], pl[2], pl[3], col);
681 continue;
682 }
683
684 gfx_polygon (num_points, pl, col);
685 };
686 }
687
688
689 void gfx_polygon (int num_points, int *poly_list, int face_colour)
690 {
691 int i;
692 int x,y;
693
694 x = 0;
695 y = 1;
696 for (i = 0; i < num_points; i++)
697 {
698 poly_list[x] += GFX_X_OFFSET;
699 poly_list[y] += GFX_Y_OFFSET;
700 x += 2;
701 y += 2;
702 }
703
704 polygon (gfx_screen, num_points, poly_list, face_colour);
705 }
706
707
708 void gfx_draw_sprite (int sprite_no, int x, int y)
709 {
710 BITMAP *sprite_bmp;
711
712 switch (sprite_no)
713 {
714 case IMG_GREEN_DOT:
715 sprite_bmp = datafile[GRNDOT].dat;
716 break;
717
718 case IMG_RED_DOT:
719 sprite_bmp = datafile[REDDOT].dat;
720 break;
721
722 case IMG_BIG_S:
723 sprite_bmp = datafile[SAFE].dat;
724 break;
725
726 case IMG_ELITE_TXT:
727 sprite_bmp = datafile[ELITETXT].dat;
728 break;
729
730 case IMG_BIG_E:
731 sprite_bmp = datafile[ECM].dat;
732 break;
733
734 case IMG_BLAKE:
735 sprite_bmp = datafile[BLAKE].dat;
736 break;
737
738 case IMG_MISSILE_GREEN:
739 sprite_bmp = datafile[MISSILE_G].dat;
740 break;
741
742 case IMG_MISSILE_YELLOW:
743 sprite_bmp = datafile[MISSILE_Y].dat;
744 break;
745
746 case IMG_MISSILE_RED:
747 sprite_bmp = datafile[MISSILE_R].dat;
748 break;
749
750 default:
751 return;
752 }
753
754 if (x == -1)
755 x = ((256 * GFX_SCALE) - sprite_bmp->w) / 2;
756
757 draw_sprite (gfx_screen, sprite_bmp, x + GFX_X_OFFSET, y + GFX_Y_OFFSET);
758 }
759
760
761 int gfx_request_file (char *title, char *path, char *ext)
762 {
763 int okay;
764
765 show_mouse (screen);
766 okay = file_select (title, path, ext);
767 show_mouse (NULL);
768
769 return okay;
770 }
771