DEADSOFTWARE

implement optional opengl render
[flatwaifu.git] / src / gl / render.c
1 #include "glob.h"
2 #include "render.h"
3 #include "files.h"
4 #include "memory.h"
5 #include "misc.h"
6 #include "error.h"
8 #include "menu.h"
9 #include "game.h"
10 #include "dots.h"
11 #include "items.h"
13 #include "sound.h" // snd_vol
14 #include "music.h" // mus_vol
16 #include "fx.h"
17 #include "player.h"
18 #include "monster.h"
19 #include "weapons.h"
20 #include "smoke.h"
21 #include "view.h"
22 #include "switch.h" // sw_secrets
24 #include <OpenGL/GL.h>
25 #include <stdlib.h> // malloc free abs
26 #include <assert.h> // assert
27 #include <SDL.h>
29 #define VGA_TRANSPARENT_COLOR 0
30 #define DEFAULT_SKY_COLOR 0x97
31 #define MANCOLOR 0xD0
32 #define PLAYER_COLOR_OFFSET 7
33 #define MAXAIR 1091
34 #define ANIT 5
35 #define PL_FLASH 90
37 #pragma pack(1)
38 typedef struct vgaimg {
39 word w, h;
40 short x, y;
41 byte data[];
42 } vgaimg;
44 typedef struct rgb {
45 byte r, g, b;
46 } rgb;
48 typedef struct rgba {
49 byte r, g, b, a;
50 } rgba;
51 #pragma pack()
53 typedef struct image {
54 GLuint id;
55 GLint x, y;
56 GLuint w, h;
57 int res;
58 } image;
60 /* Render Specific */
61 int SCRW = 320; // public
62 int SCRH = 200; // public
63 static int gamma;
64 static int fullscreen;
65 static SDL_Surface *surf;
66 static rgb playpal[256];
67 static byte bright[256];
69 /* Game */
70 static image scrnh[3]; // TITLEPIC INTERPIC ENDPIC
71 static image ltn[2][2];
73 /* Smoke */
74 static image smk_spr[SMSN];
75 static image smk_fspr[FLSN];
77 /* Effects */
78 static image fx_spr[15];
79 static char fx_sprd[15];
81 /* Weapons */
82 static image wp_spr[49*2];
83 static char wp_sprd[49*2];
85 /* Items */
86 static image item_spr[58];
87 static char item_sprd[58];
89 /* Player */
90 static image plr_spr[27*2];
91 static image plr_msk[27*2];
92 static char plr_sprd[27*2];
93 static image plr_wpn[11][6];
95 /* Monsters */
96 static image pl_spr[2];
97 static image pl_msk[2];
98 static image mn_spr[MN_TN][29*2];
99 static image mn_man_msk[29*2];
100 static char mn_sprd[MN_TN][29*2];
101 static image mn_fspr[8];
102 static image mn_sgun[2];
104 /* Misc */
105 static image sth[22];
106 static image bfh[160 - '!'];
107 static image sfh[160 - '!'];
108 static image stone;
109 static image stone2;
110 static image keys[3];
111 static int prx = 0;
112 static int pry = 0;
114 /* Menu */
115 static int gm_tm;
116 static image msklh[2];
117 static image mbarl;
118 static image mbarm;
119 static image mbarr;
120 static image mbaro;
121 static image mslotl;
122 static image mslotm;
123 static image mslotr;
125 /* Map */
126 static const char *anm[ANIT - 1][5] = {
127 {"WALL22_1", "WALL23_1", "WALL23_2", NULL, NULL},
128 {"WALL58_1", "WALL58_2", "WALL58_3", NULL, NULL},
129 {"W73A_1", "W73A_2", NULL, NULL, NULL},
130 {"RP2_1", "RP2_2", "RP2_3", "RP2_4", NULL}
131 };
132 static int max_wall_width;
133 static int max_wall_height;
134 static int max_textures;
135 static image walp[256];
136 static byte walani[256];
137 static image anip[ANIT][5];
138 static byte anic[ANIT];
139 static image horiz;
141 /* Generic helpers */
143 static void R_init_playpal (void) {
144 int i;
145 byte *vgapal = M_lock(F_getresid("PLAYPAL"));
146 for (i = 0; i < 256; i++) {
147 playpal[i] = (rgb) {
148 .r = vgapal[i * 3 + 0] * 255 / 63,
149 .g = vgapal[i * 3 + 1] * 255 / 63,
150 .b = vgapal[i * 3 + 2] * 255 / 63,
151 };
152 bright[i] = ((int)vgapal[i * 3 + 0] + vgapal[i * 3 + 1] + vgapal[i * 3 + 2]) * 8 / (63 * 3);
154 M_unlock(vgapal);
157 static vgaimg *R_getvga (int id) {
158 int loaded = M_was_locked(id);
159 vgaimg *v = M_lock(id);
160 if (v != NULL && !loaded) {
161 v->w = short2host(v->w);
162 v->h = short2host(v->h);
163 v->x = short2host(v->x);
164 v->y = short2host(v->y);
166 return v;
169 static rgba *R_extract_flame_spr (vgaimg *v) {
170 static const byte flametab[16] = {
171 0xBC, 0xBA, 0xB8, 0xB6, 0xB4, 0xB2, 0xB0, 0xD5,
172 0xD6, 0xD7, 0xA1, 0xA0, 0xE3, 0xE2, 0xE1, 0xE0
173 };
174 int i, j;
175 rgba *s = malloc(v->w * v->h * sizeof(rgba));
176 if (s != NULL) {
177 for (j = 0; j < v->h; j++) {
178 for (i = 0; i < v->w; i++) {
179 int k = j * v->w + i;
180 byte c = v->data[k] + bright[DEFAULT_SKY_COLOR];
181 s[k] = (rgba) {
182 .r = playpal[flametab[c]].r,
183 .g = playpal[flametab[c]].g,
184 .b = playpal[flametab[c]].b,
185 .a = v->data[k] == VGA_TRANSPARENT_COLOR ? 0x00 : 0xFF,
186 };
190 return s;
193 static rgba *R_extract_smoke_spr (vgaimg *v) {
194 int i, j;
195 rgba *s = malloc(v->w * v->h * sizeof(rgba));
196 if (s != NULL) {
197 for (j = 0; j < v->h; j++) {
198 for (i = 0; i < v->w; i++) {
199 int k = j * v->w + i;
200 byte c = ((v->data[k] + bright[DEFAULT_SKY_COLOR]) + 0x60) ^ 0x0F;
201 byte a = 0xFF - ((int)playpal[c].r + playpal[c].g + playpal[c].b) / 3;
202 s[k] = (rgba) {
203 .r = playpal[c].r,
204 .g = playpal[c].g,
205 .b = playpal[c].b,
206 .a = v->data[k] == VGA_TRANSPARENT_COLOR ? 0x00 : a,
207 };
211 return s;
214 static rgba *R_extract_mask_spr (vgaimg *v) {
215 int i, j;
216 rgba *s = malloc(v->w * v->h * sizeof(rgba));
217 if (s != NULL) {
218 for (j = 0; j < v->h; j++) {
219 for (i = 0; i < v->w; i++) {
220 int k = j * v->w + i;
221 byte c = v->data[k];
222 if (c >= 0x70 && c <= 0x7F) {
223 byte mask = c - 0x70;
224 mask = 0xFF - ((mask << 4) | mask);
225 s[k] = (rgba) {
226 .r = mask,
227 .g = mask,
228 .b = mask,
229 .a = 0xFF,
230 };
231 } else {
232 s[k] = (rgba) {
233 .r = 0,
234 .g = 0,
235 .b = 0,
236 .a = 0,
237 };
242 return s;
245 static rgba *R_extract_rgba_spr (vgaimg *v) {
246 int i, j;
247 rgba *s = malloc(v->w * v->h * sizeof(rgba));
248 if (s != NULL) {
249 for (j = 0; j < v->h; j++) {
250 for (i = 0; i < v->w; i++) {
251 int k = j * v->w + i;
252 byte c = v->data[k];
253 s[k] = (rgba) {
254 .r = playpal[c].r,
255 .g = playpal[c].g,
256 .b = playpal[c].b,
257 .a = c == VGA_TRANSPARENT_COLOR ? 0x00 : 0xFF,
258 };
262 return s;
265 /* OpenGL helpers */
267 static image R_gl_create_image (const rgba *buf, int w, int h) {
268 GLuint tex = 0;
269 glGenTextures(1, &tex);
270 if (tex != 0) {
271 glBindTexture(GL_TEXTURE_2D, tex);
272 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
273 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
274 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, buf);
275 glBindTexture(GL_TEXTURE_2D, 0);
277 return (image) {
278 .id = tex,
279 .w = w,
280 .h = h,
281 };
284 static image R_gl_get_special_image (int id, rgba *(*fn)(vgaimg*)) {
285 image img = (image) { .res = -1 };
286 vgaimg *v = R_getvga(id);
287 if (v != NULL) {
288 rgba *buf = (*fn)(v);
289 img = R_gl_create_image(buf, v->w, v->h);
290 img.x = v->x;
291 img.y = v->y;
292 img.res = id;
293 M_unlock(v);
294 free(buf);
296 return img;
299 static image R_gl_getimage (int id) {
300 return R_gl_get_special_image(id, &R_extract_rgba_spr);
303 static image R_gl_loadimage (const char name[8]) {
304 return R_gl_getimage(F_getresid(name));
307 static image R_gl_get_special_spr (const char n[4], int s, int d, rgba *(*fn)(vgaimg*)) {
308 return R_gl_get_special_image(F_getsprid(n, s, d), fn);
311 static void R_gl_free_image (image *img) {
312 if (img->id != 0 && img->res >= 0) {
313 glDeleteTextures(1, &img->id);
315 img->id = 0;
318 static void R_gl_draw_quad (int x, int y, int w, int h) {
319 glBegin(GL_QUADS);
320 glVertex2i(x + w, y);
321 glVertex2i(x, y);
322 glVertex2i(x, y + h);
323 glVertex2i(x + w, y + h);
324 glEnd();
327 static void R_gl_draw_textured (image *img, int x, int y, int w, int h, int flip) {
328 int ax = flip == 0;
329 int bx = !ax;
330 glBindTexture(GL_TEXTURE_2D, img->id);
331 glEnable(GL_TEXTURE_2D);
332 glBegin(GL_QUADS);
333 glTexCoord2f(ax, 0); glVertex2i(x + w, y);
334 glTexCoord2f(bx, 0); glVertex2i(x, y);
335 glTexCoord2f(bx, 1); glVertex2i(x, y + h);
336 glTexCoord2f(ax, 1); glVertex2i(x + w, y + h);
337 glEnd();
338 glDisable(GL_TEXTURE_2D);
339 glBindTexture(GL_TEXTURE_2D, 0);
342 /* fit image into rectangle without applying offset and transparency */
343 static void R_gl_draw_image_ext (image *img, int x, int y, int w, int h) {
344 glDisable(GL_BLEND);
345 glColor3ub(255, 255, 255);
346 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
347 R_gl_draw_textured(img, x, y, w, h, 0);
350 /* draw sprite with offset and coloring */
351 static void R_gl_draw_image_color (image *img, int x, int y, int flip) {
352 int xx = flip ? x - img->w + img->x : x - img->x;
353 glEnable(GL_BLEND);
354 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
355 R_gl_draw_textured(img, xx, y - img->y, img->w, img->h, flip);
356 glDisable(GL_BLEND);
359 /* draw sprite with offset */
360 static void R_gl_draw_image (image *img, int x, int y, int flip) {
361 int xx = flip ? x - img->w + img->x : x - img->x;
362 glEnable(GL_BLEND);
363 glColor3ub(255, 255, 255);
364 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
365 R_gl_draw_textured(img, xx, y - img->y, img->w, img->h, flip);
368 static void R_gl_set_color (byte c) {
369 glColor3ub(playpal[c].r, playpal[c].g, playpal[c].b);
372 static void R_gl_setclip (int x, int y, int w, int h) {
373 glScissor(x, SCRH - h - y, w, h);
376 static void R_gl_setmatrix (void) {
377 glScissor(0, 0, SCRW, SCRH);
378 glViewport(0, 0, SCRW, SCRH);
379 glMatrixMode(GL_PROJECTION);
380 glLoadIdentity();
381 glOrtho(0, SCRW, SCRH, 0, 0, 1);
382 glMatrixMode(GL_MODELVIEW);
383 glLoadIdentity();
386 /* --- Misc --- */
388 static image Z_getspr (const char n[4], int s, int d, char *dir) {
389 int h = F_getsprid(n, s, d);
390 if (dir != NULL) {
391 *dir = (h & 0x8000) ? 1 : 0;
393 return R_gl_getimage(h);
396 static void Z_putch_generic (image img[], int off, int ch) {
397 image *p = NULL;
398 if (ch > 32 && ch < 160) {
399 p = &img[ch - '!'];
401 if (p != NULL) {
402 R_gl_draw_image(p, prx, pry, 0);
403 prx += p->w - 1;
404 } else {
405 prx += off;
409 static void Z_printf_generic (image img[], int off, const char *fmt, va_list ap) {
410 int i;
411 char buf[80];
412 vsprintf(buf, fmt, ap);
413 for (i = 0; buf[i]; ++i) {
414 switch (buf[i]) {
415 case '\n':
416 pry += off + 1;
417 case '\r':
418 prx = 0;
419 break;
420 default:
421 Z_putch_generic(img, off, (byte)buf[i]);
426 static void Z_gotoxy (int x, int y) {
427 prx = x;
428 pry = y;
431 static void Z_printbf (const char *fmt, ...) {
432 va_list a;
433 va_start(a, fmt);
434 Z_printf_generic(bfh, 12, fmt, a);
435 va_end(a);
438 static void Z_printsf (const char *fmt, ...) {
439 va_list a;
440 va_start(a, fmt);
441 Z_printf_generic(sfh, 7, fmt, a);
442 va_end(a);
445 static void Z_printhf (const char *fmt, ...) {
446 int i, c;
447 char buf[80];
448 va_list a;
449 va_start(a, fmt);
450 vsprintf(buf, fmt, a);
451 va_end(a);
452 for (i = 0; buf[i]; ++i) {
453 switch (buf[i]) {
454 case '0':
455 case '1':
456 case '2':
457 case '3':
458 case '4':
459 case '5':
460 case '6':
461 case '7':
462 case '8':
463 case '9':
464 c = buf[i] - '0';
465 break;
466 case '-':
467 c = 10;
468 break;
469 case '%':
470 c = 11;
471 break;
472 case '\n':
473 pry += 19;
474 case '\r':
475 c = -1;
476 prx = 0;
477 break;
478 default:
479 c = -1;
480 break;
482 if (c >= 0) {
483 R_gl_draw_image(&sth[c], prx, pry, 0);
485 prx += 14;
489 /* --- Menu --- */
491 static image *PL_getspr (int s, int d, int msk) {
492 int i = (s - 'A') * 2 + d;
493 return msk ? &plr_msk[i] : &plr_spr[i];
496 static void GM_draw (void) {
497 enum {MENU, MSG}; // copypasted from menu.c!
498 enum {
499 CANCEL, NEWGAME, LOADGAME, SAVEGAME, OPTIONS, QUITGAME, QUIT, ENDGAME, ENDGM,
500 PLR1, PLR2, COOP, DM, VOLUME, GAMMA, LOAD, SAVE, PLCOLOR, PLCEND, MUSIC, INTERP,
501 SVOLM, SVOLP, MVOLM, MVOLP, GAMMAM, GAMMAP, PL1CM, PL1CP, PL2CM, PL2CP
502 }; // copypasted from menu.c!
503 int i, j, k, x, y, cx, cy;
504 image *img;
505 gm_tm += 1;
506 if (mnu != NULL) {
507 cx = SCRW / 2;
508 cy = SCRH / 2;
509 if (mnu->type == MENU) {
510 y = cy - (mnu->n * 16 - 20) / 2;
511 Z_gotoxy(cx - mnu->x, y - 10); Z_printbf("%s", mnu->ttl);
512 for (i = 0; i < mnu->n; i++) {
513 if (mnu->t[i] == LOAD || mnu->t[i] == SAVE) {
514 j = y + i * 16 + 29;
515 R_gl_draw_image(&mslotl, cx - mnu->x, j, 0);
516 for (k = 8; k < 184; k += 8) {
517 R_gl_draw_image(&mslotm, cx - mnu->x + k, j, 0);
519 R_gl_draw_image(&mslotr, cx - mnu->x + 184, j, 0);
520 Z_gotoxy(cx - mnu->x + 4, j - 8);
521 if (input && i == save_mnu.cur) {
522 Z_printsf("%s_", ibuf);
523 } else {
524 Z_printsf("%s", savname[i]);
526 } else {
527 x = mnu->t[i] >= SVOLM ? (mnu->t[i] >= PL1CM ? 50 : 152) : 0;
528 Z_gotoxy(cx - mnu->x + x, y + i * 16 + 20);
529 Z_printbf("%s", mnu->m[i]);
530 switch (mnu->t[i]) {
531 case MUSIC:
532 Z_printbf(" '%s'", g_music);
533 break;
534 case INTERP:
535 Z_printbf("%s", fullscreen ? "ON" : "OFF");
536 break;
537 case PL1CM:
538 case PL1CP:
539 case PL2CM:
540 case PL2CP:
541 img = PL_getspr(*panimp, 0, 0);
542 R_gl_draw_image(img, cx - mnu->x + (mnu->t[i] == PL1CM ? 15 : 35), y + i * 16 + 20 + 14, 0);
543 img = PL_getspr(*panimp, 0, 1);
544 R_gl_set_color(pcolortab[(mnu->t[i] == PL1CM) ? p1color : p2color] + PLAYER_COLOR_OFFSET);
545 R_gl_draw_image_color(img, cx - mnu->x + (mnu->t[i] == PL1CM ? 15 : 35), y + i * 16 + 20 + 14, 0);
546 break;
547 case SVOLM:
548 case SVOLP:
549 case MVOLM:
550 case MVOLP:
551 case GAMMAM:
552 case GAMMAP:
553 j = y + i * 16 + 20;
554 R_gl_draw_image(&mbarl, cx - mnu->x, j, 0);
555 for (k = 8; k < 144; k += 8) {
556 R_gl_draw_image(&mbarm, cx - mnu->x + k, j, 0);
558 R_gl_draw_image(&mbarr, cx - mnu->x + 144, j, 0);
559 switch (mnu->t[i]) {
560 case SVOLM:
561 k = snd_vol;
562 break;
563 case MVOLM:
564 k = mus_vol;
565 break;
566 case GAMMAM:
567 k = gamma << 5;
568 break;
569 default:
570 k = 0;
571 break;
573 R_gl_draw_image(&mbaro, cx - mnu->x + 8 + k, j, 0);
574 break;
578 R_gl_draw_image(&msklh[(gm_tm / 6) & 1], cx - mnu->x - 25, y + mnu->cur * 16 + 20 - 8, 0);
579 } else if (mnu->type == MSG) {
580 Z_gotoxy(cx - strlen(mnu->ttl) * 7 / 2, cy - 10); Z_printsf(mnu->ttl);
581 Z_gotoxy(cx - 24, SCRH / 2); Z_printsf("(Y/N)");
582 } else {
583 ERR_fatal("Unknown menu type %i\n", mnu->type);
588 /* --- View --- */
590 static void R_draw_fld (byte *fld, int minx, int miny, int maxx, int maxy, int fg) {
591 int i, j;
592 assert(minx >= 0 && minx <= FLDW);
593 assert(miny >= 0 && miny <= FLDH);
594 assert(maxx >= 0 && maxx <= FLDW);
595 assert(maxy >= 0 && maxy <= FLDH);
596 for (j = miny; j < maxy; j++) {
597 for (i = minx; i < maxx; i++) {
598 byte id = fld[j * FLDW + i];
599 if (id != 0) {
600 if (walp[id].res < 0) {
601 if (fg) {
602 switch (walp[id].id) {
603 case 1:
604 glColor4ub(0, 0, 255, 127);
605 break;
606 case 2:
607 glColor4ub(0, 127, 0, 127);
608 break;
609 case 3:
610 glColor4ub(127, 0, 0, 127);
611 break;
612 default:
613 glColor4ub(0, 0, 0, 127);
614 break;
616 glEnable(GL_BLEND);
617 glBlendFunc(GL_DST_COLOR, GL_SRC_COLOR);
618 R_gl_draw_quad(i * CELW, j * CELW, CELW, CELH);
620 } else {
621 R_gl_draw_image(&walp[id], i * CELW, j * CELH, 0);
628 static void R_draw_dots (void) {
629 int i;
630 glBegin(GL_POINTS);
631 for (i = 0; i < MAXDOT; i++) {
632 if (dot[i].t != 0) {
633 R_gl_set_color(dot[i].c);
634 glVertex2i(dot[i].o.x, dot[i].o.y + 1);
637 glEnd();
640 static void R_draw_items (void) {
641 int i, s;
642 for (i = 0; i < MAXITEM; ++i) {
643 s = -1;
644 if (it[i].t && it[i].s >= 0) {
645 switch (it[i].t & 0x7FFF) {
646 case I_ARM1:
647 s = it[i].s / 9 + 18;
648 break;
649 case I_ARM2:
650 s = it[i].s / 9 + 20;
651 break;
652 case I_MEGA:
653 s = it[i].s / 2 + 22;
654 break;
655 case I_INVL:
656 s = it[i].s / 2 + 26;
657 break;
658 case I_SUPER:
659 case I_RTORCH:
660 case I_GTORCH:
661 case I_BTORCH:
662 s = it[i].s / 2 + (it[i].t - I_SUPER) * 4 + 35;
663 break;
664 case I_GOR1: case I_FCAN:
665 s = it[i].s / 2 + (it[i].t - I_GOR1) * 3 + 51;
666 break;
667 case I_AQUA:
668 s = 30;
669 break;
670 case I_SUIT:
671 s = 34;
672 break;
673 case I_KEYR:
674 case I_KEYG:
675 case I_KEYB:
676 s = (it[i].t & 0x7FFF) - I_KEYR + 31;
677 break;
678 case I_GUN2:
679 s = 57;
680 break;
681 default:
682 s = (it[i].t & 0x7FFF) - 1;
685 if (s >= 0) {
686 R_gl_draw_image(&item_spr[s], it[i].o.x, it[i].o.y, item_sprd[s]);
691 static int standspr (player_t *p) {
692 if (p->f & PLF_UP) {
693 return 'X';
694 } else if (p->f & PLF_DOWN) {
695 return 'Z';
696 } else {
697 return 'E';
701 static int wpnspr (player_t *p) {
702 if (p->f & PLF_UP) {
703 return 'C';
704 } else if(p->f & PLF_DOWN) {
705 return 'E';
706 } else {
707 return 'A';
711 static void R_draw_player (player_t *p) {
712 enum {STAND, GO, DIE, SLOP, DEAD, MESS, OUT, FALL}; // copypasted from player.c!
713 static const int wytab[] = {-1, -2, -1, 0};
714 int s = 'A';
715 int w = 0;
716 int wx = 0;
717 int wy = 0;
718 switch (p->st) {
719 case STAND:
720 if (p->f & PLF_FIRE) {
721 s = standspr(p) + 1;
722 w = wpnspr(p) + 1;
723 } else if (p->pain) {
724 s = 'G';
725 w = 'A';
726 wx = p->d ? 2 : -2;
727 wy = 1;
728 } else {
729 s = standspr(p);
730 w = wpnspr(p);
732 break;
733 case DEAD:
734 s = 'N';
735 break;
736 case MESS:
737 s = 'W';
738 break;
739 case GO:
740 if (p->pain) {
741 s = 'G';
742 w = 'A';
743 wx = p->d ? 2 : -2;
744 wy = 1;
745 } else {
746 s = plr_goanim[p->s / 8];
747 w = (p->f & PLF_FIRE) ? 'B' : 'A';
748 wx = p->d ? 2 : -2;
749 wy = 1 + wytab[s - 'A'];
751 break;
752 case DIE:
753 s = plr_dieanim[p->s];
754 break;
755 case SLOP:
756 s = plr_slopanim[p->s];
757 break;
758 case OUT:
759 s = 0;
760 break;
762 if (p->wpn == 0) {
763 w = 0;
765 if (w) {
766 R_gl_draw_image(&plr_wpn[(int)p->wpn][w -'A'], p->o.x + wx, p->o.y + wy, p->d);
768 if (s) {
769 R_gl_draw_image(&plr_spr[(s - 'A') * 2 + p->d], p->o.x, p->o.y, plr_sprd[(s - 'A') * 2 + p->d]);
770 R_gl_set_color(p->color + PLAYER_COLOR_OFFSET);
771 R_gl_draw_image_color(&plr_msk[(s - 'A') * 2 + p->d], p->o.x, p->o.y, plr_sprd[(s - 'A') * 2 + p->d]);
775 static void R_draw_monsters (void) {
776 enum {SLEEP, GO, RUN, CLIMB, DIE, DEAD, ATTACK, SHOOT, PAIN, WAIT, REVIVE, RUNOUT}; // copypasted from monster.c!
777 int i;
778 for (i = 0; i < MAXMN; i++) {
779 if (mn[i].t != MN_NONE) {
780 int x = mn[i].o.x;
781 int y = mn[i].o.y;
782 if (mn[i].t < MN__LAST) {
783 if ((mn[i].t != MN_SOUL && mn[i].t != MN_PAIN) || mn[i].st != DEAD) {
784 int ap = mn[i].ap[mn[i].ac];
785 int d = (ap - 'A') * 2 + mn[i].d;
786 int dir = mn_sprd[mn[i].t - 1][d];
787 if (mn[i].t == MN_MAN && (ap == 'E' || ap == 'F')) {
788 R_gl_draw_image(&mn_sgun[ap - 'E'], x, y, mn[i].d);
790 R_gl_draw_image(&mn_spr[mn[i].t - 1][d], x, y, dir);
791 if (mn[i].t == MN_MAN) {
792 R_gl_set_color(MANCOLOR + PLAYER_COLOR_OFFSET);
793 R_gl_draw_image_color(&mn_man_msk[d], x, y, dir);
796 if (mn[i].t == MN_VILE && mn[i].st == SHOOT) {
797 R_gl_draw_image(&mn_fspr[mn[i].ac / 3], mn[i].tx, mn[i].ty, 0);
799 } else if (mn[i].t == MN_PL_DEAD || mn[i].t == MN_PL_MESS) {
800 int type = mn[i].t - MN_PL_DEAD;
801 R_gl_draw_image(&pl_spr[type], x, y, 0);
802 R_gl_set_color(mn[i].d);
803 R_gl_draw_image_color(&pl_msk[type], x, y, 0);
809 static void R_draw_weapons (void) {
810 enum {NONE, ROCKET, PLASMA, APLASMA, BALL1, BALL2, BALL7, BFGBALL, BFGHIT, MANF, REVF, FIRE}; // copypasted from weapons.c!
811 int i, s, d, x, y;
812 for (i = 0; i < MAXWPN; ++i) {
813 s = -1;
814 d = 0;
815 switch (wp[i].t) {
816 case REVF:
817 case ROCKET:
818 d = wp[i].s;
819 if (d < 2) {
820 d = wp[i].o.xv > 0 ? 1 : 0;
821 x = abs(wp[i].o.xv);
822 y = wp[i].o.yv;
823 s = 0;
824 if (y < 0) {
825 if (-y >= x) {
826 s = 30;
828 } else if (y > 0) {
829 if (y >= x / 2) {
830 s = 31;
833 } else {
834 s = (d - 2) / 2 + 1;
835 d = 0;
837 break;
838 case MANF:
839 s=wp[i].s;
840 if (s >= 2) {
841 s /= 2;
842 break;
844 case PLASMA:
845 case APLASMA:
846 case BALL1:
847 case BALL7:
848 case BALL2:
849 s = wp[i].s;
850 if (s >= 2) {
851 s = s / 2 + 1;
853 switch (wp[i].t) {
854 case PLASMA:
855 s += 4;
856 break;
857 case APLASMA:
858 s += 11;
859 break;
860 case BALL1:
861 s += 32;
862 break;
863 case BALL2:
864 s += 42;
865 break;
866 case BALL7:
867 s += 37;
868 d = wp[i].o.xv >= 0 ? 1 : 0;
869 break;
870 case MANF:
871 s += 47;
872 d= wp[i].o.xv>=0 ? 1 : 0;
873 break;
875 break;
876 case BFGBALL:
877 s = wp[i].s;
878 if (s >= 2) {
879 s = s / 2 + 1;
881 s += 18;
882 break;
883 case BFGHIT:
884 s = wp[i].s / 2 + 26;
885 break;
887 if (s >= 0) {
888 R_gl_draw_image(&wp_spr[s * 2 + d], wp[i].o.x, wp[i].o.y, wp_sprd[s * 2 + d]);
893 static void R_draw_smoke (void) {
894 int i, s;
895 for (i = 0; i < MAXSMOK; ++i) {
896 if (sm[i].t) {
897 switch (sm[i].s) {
898 case 0:
899 s = sm[i].t;
900 if (s >= (SMSN - 1) * 3) {
901 s = 0;
902 } else {
903 s = SMSN - 1 - s / 3;
905 R_gl_draw_image(&smk_spr[s], sm[i].x >> 8, (sm[i].y >> 8) + 1, 0);
906 break;
907 case 1:
908 s = sm[i].t;
909 if (s >= FLSN - 1) {
910 s = 0;
911 } else {
912 s = FLSN - 1 - s;
914 R_gl_draw_image(&smk_fspr[s], sm[i].x >> 8, (sm[i].y >> 8) + 1, 0);
915 break;
921 static void R_draw_effects (void) {
922 enum {NONE, TFOG, IFOG, BUBL}; // copypasted from fx.c
923 int i, s;
924 for (i = 0; i < MAXFX; ++i) {
925 switch (fx[i].t) {
926 case TFOG:
927 s = fx[i].s / 2;
928 R_gl_draw_image(&fx_spr[s], fx[i].x, fx[i].y, fx_sprd[s]);
929 break;
930 case IFOG:
931 s = fx[i].s / 2 + 10;
932 R_gl_draw_image(&fx_spr[s], fx[i].x, fx[i].y, fx_sprd[s]);
933 break;
934 case BUBL:
935 glBegin(GL_POINTS);
936 R_gl_set_color(0xC0 + fx[i].s);
937 glVertex2i(fx[i].x >> 8, (fx[i].y >> 8) + 1);
938 glEnd();
939 break;
944 static int get_pu_st (int t) {
945 if (t >= PL_FLASH) {
946 return 1;
947 } else if((t / 9) & 1) {
948 return 0;
949 } else {
950 return 1;
954 static void R_draw_view (int x, int y, int w, int h, int camx, int camy) {
955 glPushMatrix();
956 R_gl_setclip(x, y, w, h);
957 glTranslatef(x, y, 0);
958 if (w_horiz && horiz.id != 0) {
959 R_gl_draw_image_ext(&horiz, 0, 0, w, h);
960 if (sky_type == 2 && lt_time < 0) {
961 image *tanderbolt = &ltn[lt_type][lt_time < -5 ? 0 : 1];
962 if (!lt_side) {
963 R_gl_draw_image(tanderbolt, 0, lt_ypos, 0);
964 } else {
965 R_gl_draw_image(tanderbolt, w - 1, lt_ypos, 1);
968 } else {
969 glDisable(GL_BLEND);
970 R_gl_set_color(DEFAULT_SKY_COLOR);
971 R_gl_draw_quad(0, 0, w, h);
973 int maxx = min((camx + w) / CELW + 1, FLDW);
974 int maxy = min((camy + h) / CELH + 1, FLDH);
975 int minx = max((camx - max_wall_width) / CELW, 0);
976 int miny = max((camy - max_wall_height) / CELH, 0);
977 glTranslatef(-camx, -camy, 0);
978 R_draw_fld((byte*)fldb, minx, miny, maxx, maxy, 0);
979 R_draw_dots();
980 R_draw_items();
981 R_draw_player(&pl1);
982 if (_2pl) {
983 R_draw_player(&pl2);
985 R_draw_monsters();
986 R_draw_weapons();
987 R_draw_smoke();
988 R_draw_effects();
989 R_draw_fld((byte*)fldf, minx, miny, maxx, maxy, 1);
990 glTranslatef(camx, camy, 0);
991 if (sky_type == 2 && (lt_time == -4 || lt_time == -2)) {
992 glColor4ub(255, 255, 255, 255);
993 glEnable(GL_BLEND);
994 glBlendFunc(GL_DST_COLOR, GL_SRC_COLOR);
995 R_gl_draw_quad(0, 0, w, h);
997 glPopMatrix();
1000 static void R_draw_player_view (player_t *p, int x, int y, int w, int h) {
1001 p->looky = min(max(p->looky, -SCRH / 4), SCRH / 4); // TODO remove writeback
1002 int st = stone.w;
1003 int cw = w - st;
1004 int cx = min(max(p->o.x, cw / 2), FLDW * CELW - cw / 2);
1005 int cy = min(max(p->o.y - 12 + p->looky, h / 2), FLDH * CELH - h / 2);
1006 int camx = max(cx - cw / 2, 0);
1007 int camy = max(cy - h / 2, 0);
1008 glPushMatrix();
1009 R_draw_view(x, y + 1, cw, h - 2, camx, camy);
1010 glTranslatef(x, y, 0);
1011 if (p->invl) {
1012 if (get_pu_st(p->invl)) {
1013 glEnable(GL_BLEND);
1014 glColor4ub(191, 191, 191, 255);
1015 glBlendFunc(GL_ONE_MINUS_DST_COLOR, GL_ZERO);
1016 R_gl_draw_quad(0, 0, cw, h);
1018 } else {
1019 if (p->suit && get_pu_st(p->suit)) {
1020 glEnable(GL_BLEND);
1021 glColor4ub(0, 255, 0, 192);
1022 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1023 R_gl_draw_quad(0, 0, cw, h);
1025 int f = min(max(p->pain * 3, 0), 255);
1026 if (f > 0) {
1027 glEnable(GL_BLEND);
1028 glColor4ub(255, 0, 0, f);
1029 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1030 R_gl_draw_quad(0, 0, cw, h);
1033 R_gl_setclip(x, y, w, h);
1034 glTranslatef(-x + cw, 0, 0);
1035 R_gl_draw_image(&stone, 0, 0, 0);
1036 int i = stone.h;
1037 while (i < h) {
1038 R_gl_draw_image(&stone2, 0, i, 0);
1039 i += stone2.h;
1041 if (p->drawst & PL_DRAWAIR) {
1042 if (p->air < PL_AIR) {
1043 int a = min(max(p->air, 0), MAXAIR) * 100 / MAXAIR;
1044 glDisable(GL_BLEND);
1045 R_gl_set_color(0xC8);
1046 R_gl_draw_quad(10, 49, a, 2);
1049 if (p->drawst & PL_DRAWLIFE) {
1050 Z_gotoxy(10, 7);
1051 Z_printhf("%3d%%", p->life);
1053 if (p->drawst & PL_DRAWARMOR) {
1054 Z_gotoxy(10, 7 + 19);
1055 Z_printhf("%3d%%", p->armor);
1057 if (p->drawst & PL_DRAWWPN) {
1058 switch(p->wpn) {
1059 case 2:
1060 case 5:
1061 i = p->ammo;
1062 break;
1063 case 3:
1064 case 4:
1065 case 9:
1066 i = p->shel;
1067 break;
1068 case 6:
1069 i = p->rock;
1070 break;
1071 case 7:
1072 case 8:
1073 i = p->cell;
1074 break;
1075 case 10:
1076 i = p->fuel;
1077 break;
1078 default:
1079 i = -1;
1080 break;
1082 // weapon
1083 if (p->wpn >= 0) {
1084 R_gl_draw_image(&sth[12 + p->wpn], st - 88, 58 + 19, 0);
1086 // ammo
1087 if (p->wpn >= 2) {
1088 Z_gotoxy(st - 10 - 5 * 14, 58 + 2);
1089 Z_printhf("%5d", i);
1092 if (p->drawst & PL_DRAWFRAG && g_dm) {
1093 Z_gotoxy(st - 5 - 5 * 14, 77 + 5);
1094 Z_printhf("%5d", p->frag);
1096 if (p->drawst & PL_DRAWKEYS) {
1097 int x, k, n;
1098 for (k = p->keys >> 4, n = 0, x = st - 75; n < 3; n++, k >>= 1, x += 9) {
1099 if (k & 1) {
1100 R_gl_draw_image(&keys[n], x, 91, 0);
1104 if (p->drawst & PL_DRAWLIVES && !_2pl) {
1105 Z_gotoxy(st - 35, 17);
1106 Z_printhf("%d", p->lives);
1108 glPopMatrix();
1111 /* --- Game --- */
1113 static void pl_info (player_t *p, int x, int y) {
1114 dword t = p->kills * 10920 / g_time;
1115 Z_gotoxy(x + 25, y); Z_printbf("KILLS");
1116 Z_gotoxy(x + 25, y + 15); Z_printbf("KPM");
1117 Z_gotoxy(x + 25, y + 30); Z_printbf("SECRETS %u / %u", p->secrets, sw_secrets);
1118 Z_gotoxy(x + 255, y); Z_printbf("%u", p->kills);
1119 Z_gotoxy(x + 255, y + 15); Z_printbf("%u.%u", t / 10, t % 10);
1122 static void R_draw_intermission (void) {
1123 int cx = SCRW / 2;
1124 word hr, mn, sc, h;
1125 Z_gotoxy(cx - 14*12/2, 20);
1126 Z_printbf("LEVEL COMPLETE");
1127 Z_calc_time(g_time, &hr, &mn, &sc);
1128 Z_gotoxy(cx - 12*12/2, 40);
1129 Z_printbf("TIME %u:%02u:%02u", hr, mn, sc);
1130 h = 40 + SCRH / 10;
1131 if (_2pl) {
1132 Z_gotoxy(cx - 10*12/2, h);
1133 Z_printbf("PLAYER ONE");
1134 h += 20;
1136 pl_info(&pl1, cx - 160, h);
1137 if (_2pl) {
1138 h += 30 + SCRH / 10;
1139 Z_gotoxy(cx - 10*12/2, h);
1140 Z_printbf("PLAYER TWO");
1141 h += 20;
1142 pl_info(&pl2, cx - 160, h);
1146 static void W_act (void) {
1147 int i, a;
1148 if (g_time % 3 == 0) {
1149 for (i = 1; i < max_textures; i++) {
1150 a = walani[i];
1151 if (a != 0) {
1152 anic[a]++;
1153 if (anip[a][anic[a]].res == -1) {
1154 anic[a] = 0;
1156 walp[i] = anip[a][anic[a]];
1162 void R_draw (void) {
1163 W_act();
1164 glClearColor(0, 0, 0, 1);
1165 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
1166 glEnable(GL_SCISSOR_TEST);
1167 R_gl_setmatrix();
1168 switch (g_st) {
1169 case GS_ENDANIM:
1170 case GS_END2ANIM:
1171 case GS_DARKEN:
1172 case GS_BVIDEO:
1173 case GS_EVIDEO:
1174 case GS_END3ANIM:
1175 break;
1176 case GS_TITLE:
1177 R_gl_draw_image_ext(&scrnh[0], 0, 0, SCRW, SCRH);
1178 break;
1179 case GS_INTER:
1180 R_gl_draw_image_ext(&scrnh[1], 0, 0, SCRW, SCRH);
1181 R_draw_intermission();
1182 break;
1183 case GS_ENDSCR:
1184 R_gl_draw_image_ext(&scrnh[2], 0, 0, SCRW, SCRH);
1185 break;
1186 case GS_GAME:
1187 if (_2pl) {
1188 R_draw_player_view(&pl1, 0, 0, SCRW, SCRH / 2);
1189 R_draw_player_view(&pl2, 0, SCRH / 2, SCRW, SCRH / 2);
1190 } else {
1191 R_draw_player_view(&pl1, 0, 0, SCRW, SCRH);
1193 R_gl_setclip(0, 0, SCRW, SCRH);
1194 break;
1196 GM_draw();
1197 SDL_GL_SwapBuffers();
1200 void R_alloc (void) {
1201 char s[10];
1202 int i, j, n;
1203 logo("R_alloc: load graphics\n");
1204 /* Game */
1205 scrnh[0] = R_gl_loadimage("TITLEPIC");
1206 scrnh[1] = R_gl_loadimage("INTERPIC");
1207 scrnh[2] = R_gl_loadimage("ENDPIC");
1208 for (i = 0; i < 2; i++) {
1209 sprintf(s, "LTN%c", '1' + i);
1210 for (j = 0; j < 2; j++) {
1211 ltn[i][j] = Z_getspr(s, j, 0, NULL);
1214 /* Smoke */
1215 for (i = 0; i < SMSN; i++) {
1216 smk_spr[i] = R_gl_get_special_spr("SMOK", i, 0, &R_extract_smoke_spr);
1218 for (i = 0; i < FLSN; i++) {
1219 smk_fspr[i] = R_gl_get_special_spr("SMOK", i, 0, &R_extract_flame_spr);
1221 /* Effects */
1222 for (i = 0; i < 10; i++) {
1223 fx_spr[i] = Z_getspr("TFOG", i, 0, fx_sprd + i);
1225 for (; i < 15; i++) {
1226 fx_spr[i] = Z_getspr("IFOG", i - 10, 0, fx_sprd + i);
1228 /* Weapons */
1229 for (i = 0; i < 4; i++) {
1230 wp_spr[i * 2] = Z_getspr("MISL", i, 1, wp_sprd + i * 2);
1231 wp_spr[i * 2 + 1] = Z_getspr("MISL", i, 2, wp_sprd + i * 2 + 1);
1233 for (; i < 6; i++) {
1234 wp_spr[i * 2] = Z_getspr("PLSS", i - 4, 1, wp_sprd + i * 2);
1235 wp_spr[i * 2 + 1] = Z_getspr("PLSS", i - 4, 2, wp_sprd + i * 2 + 1);
1237 for (; i < 11; i++) {
1238 wp_spr[i * 2] = Z_getspr("PLSE", i - 6, 1, wp_sprd + i * 2);
1239 wp_spr[i * 2 + 1] = Z_getspr("PLSE", i - 6, 2, wp_sprd + i * 2 + 1);
1241 for (; i < 13; i++) {
1242 wp_spr[i * 2] = Z_getspr("APLS", i - 11, 1, wp_sprd + i * 2);
1243 wp_spr[i * 2 + 1] = Z_getspr("APLS", i - 11, 2, wp_sprd + i * 2 + 1);
1245 for (; i < 18; i++) {
1246 wp_spr[i * 2] = Z_getspr("APBX", i - 13, 1, wp_sprd + i * 2);
1247 wp_spr[i * 2 + 1] = Z_getspr("APBX", i - 13, 2, wp_sprd + i * 2 + 1);
1249 for(; i < 20; i++) {
1250 wp_spr[i * 2] = Z_getspr("BFS1", i - 18, 1, wp_sprd + i * 2);
1251 wp_spr[i * 2 + 1] = Z_getspr("BFS1", i - 18, 2, wp_sprd + i * 2 + 1);
1253 for (; i < 26; i++) {
1254 wp_spr[i * 2] = Z_getspr("BFE1", i - 20, 1, wp_sprd + i * 2);
1255 wp_spr[i * 2 + 1] = Z_getspr("BFE1", i - 20, 2, wp_sprd + i * 2 + 1);
1257 for (; i < 30; i++) {
1258 wp_spr[i * 2] = Z_getspr("BFE2", i - 26, 1, wp_sprd + i * 2);
1259 wp_spr[i * 2 + 1] = Z_getspr("BFE2", i - 26, 2, wp_sprd + i * 2 + 1);
1261 for (; i < 32; i++) {
1262 wp_spr[i * 2] = Z_getspr("MISL", i - 30 + 4, 1, wp_sprd + i * 2);
1263 wp_spr[i * 2 + 1] = Z_getspr("MISL", i - 30 + 4, 2, wp_sprd + i * 2 + 1);
1265 for (; i < 37; i++) {
1266 wp_spr[i * 2] = Z_getspr("BAL1", i - 32, 1, wp_sprd + i * 2);
1267 wp_spr[i * 2 + 1] = Z_getspr("BAL1", i - 32, 2, wp_sprd + i * 2 + 1);
1269 for (; i < 42; i++) {
1270 wp_spr[i * 2] = Z_getspr("BAL7", i - 37, 1, wp_sprd + i * 2);
1271 wp_spr[i * 2 + 1] = Z_getspr("BAL7", i - 37, 2, wp_sprd + i * 2 + 1);
1273 for (; i < 47; i++) {
1274 wp_spr[i * 2] = Z_getspr("BAL2", i - 42, 1, wp_sprd + i * 2);
1275 wp_spr[i * 2 + 1] = Z_getspr("BAL2", i - 42, 2, wp_sprd + i * 2 + 1);
1277 for (; i < 49; i++) {
1278 wp_spr[i * 2] = Z_getspr("MANF", i - 47, 1, wp_sprd + i * 2);
1279 wp_spr[i * 2 + 1] = Z_getspr("MANF", i - 47, 2, wp_sprd + i * 2 + 1);
1281 /* Items */
1282 static const char snm[18][4] = {
1283 "CLIP", "SHEL", "ROCK", "CELL", "AMMO", "SBOX", "BROK", "CELP",
1284 "STIM", "MEDI", "BPAK",
1285 "CSAW", "SHOT", "SGN2", "MGUN", "LAUN", "PLAS", "BFUG"
1286 };
1287 static const char n4[4][4] = {
1288 "SOUL", "SMRT", "SMGT", "SMBT"
1289 };
1290 static const char n3[2][4] = {
1291 "GOR1", "FCAN"
1292 };
1293 for (i = 0; i < 18; i++) {
1294 item_spr[i] = Z_getspr(snm[i], 0, 0, item_sprd + i);
1296 for (; i < 20; i++) {
1297 item_spr[i] = Z_getspr("ARM1", i - 18, 0, item_sprd + i);
1298 item_spr[i + 2] = Z_getspr("ARM2", i - 18, 0, item_sprd + i);
1300 i+=2;
1301 for (; i < 26; i++) {
1302 item_spr[i] = Z_getspr("MEGA", i - 22, 0, item_sprd + i);
1304 for (; i < 30; i++) {
1305 item_spr[i] = Z_getspr("PINV", i - 26, 0, item_sprd + i);
1307 item_spr[30] = Z_getspr("AQUA", 0, 0, item_sprd + 30);
1308 item_spr[31] = Z_getspr("KEYR", 0, 0, item_sprd + 31);
1309 item_spr[32] = Z_getspr("KEYG", 0, 0, item_sprd + 32);
1310 item_spr[33] = Z_getspr("KEYB", 0, 0, item_sprd + 33);
1311 item_spr[34] = Z_getspr("SUIT", 0, 0, item_sprd + 34);
1312 for (n = 35, j = 0; j < 4; j++) {
1313 for (i = 0; i < 4; i++, n++) {
1314 item_spr[n] = Z_getspr(n4[j], i, 0, item_sprd + n);
1317 for (j = 0; j < 2; j++) {
1318 for (i = 0; i < 3; i++, n++) {
1319 item_spr[n] = Z_getspr(n3[j], i, 0, item_sprd + n);
1322 item_spr[57] = Z_getspr("GUN2", 0, 0, item_sprd + 57);
1323 /* Player */
1324 for (i = 0; i < 27; i++) {
1325 plr_spr[i * 2] = Z_getspr("PLAY", i, 1, plr_sprd + i * 2);
1326 plr_msk[i * 2] = R_gl_get_special_spr("PLAY", i, 1, &R_extract_mask_spr);
1327 plr_spr[i * 2 + 1] = Z_getspr("PLAY", i, 2, plr_sprd + i * 2 + 1);
1328 plr_msk[i * 2 + 1] = R_gl_get_special_spr("PLAY", i, 2, &R_extract_mask_spr);
1330 strncpy(s, "PWPx", 4);
1331 for (i = 1; i < 11; i++) {
1332 s[3] = (i < 10 ? '0' : 'A' - 10) + i;
1333 for (j = 0; j < 6; j++) {
1334 plr_wpn[i][j] = Z_getspr(s, j, 1, NULL);
1337 /* Monsters */
1338 static const char msn[MN_TN][4] = {
1339 "SARG", "TROO", "POSS", "SPOS", "CYBR", "CPOS", "BOSS", "BOS2", "HEAD", "SKUL",
1340 "PAIN", "SPID", "BSPI", "FATT", "SKEL", "VILE", "FISH", "BAR1", "ROBO", "PLAY"
1341 };
1342 static const int mms[MN_TN] = {
1343 14*2, 21*2, 21*2, 21*2, 16*2, 20*2, 15*2, 15*2, 12*2, 11*2,
1344 13*2, 19*2, 16*2, 20*2, 17*2, 29*2, 6*2, 2*2, 17*2, 23*2
1345 };
1346 mn_sgun[0] = Z_getspr("PWP4", 0, 1, NULL);
1347 mn_sgun[1] = Z_getspr("PWP4", 1, 1, NULL);
1348 for (j = 0; j < MN_TN; j++) {
1349 for (i = 0; i < mms[j]; i++) {
1350 mn_spr[j][i] = Z_getspr(msn[j], i / 2, (i & 1) + 1, &mn_sprd[j][i]);
1351 if (j == MN_MAN - 1) {
1352 mn_man_msk[i] = R_gl_get_special_spr(msn[j], i / 2, (i & 1) + 1, &R_extract_mask_spr);
1355 if (j == MN_BARREL - 1) {
1356 for (i = 4; i < 14; i++) {
1357 mn_spr[j][i] = Z_getspr("BEXP", i / 2 - 2, (i & 1) + 1, &mn_sprd[j][i]);
1361 for (i = 0; i < 8; i++) {
1362 mn_fspr[i] = Z_getspr("FIRE", i, 0, NULL);
1364 pl_spr[0] = Z_getspr("PLAY", 'N' - 'A', 0, NULL);
1365 pl_msk[0] = R_gl_get_special_spr("PLAY", 'N' - 'A', 0, &R_extract_mask_spr);
1366 pl_spr[1] = Z_getspr("PLAY", 'W' - 'A', 0, NULL);
1367 pl_msk[1] = R_gl_get_special_spr("PLAY", 'W' - 'A', 0, &R_extract_mask_spr);
1368 /* Misc */
1369 static const char mnm[22][8]={
1370 "STTNUM0", "STTNUM1", "STTNUM2", "STTNUM3", "STTNUM4",
1371 "STTNUM5", "STTNUM6", "STTNUM7", "STTNUM8", "STTNUM9",
1372 "STTMINUS", "STTPRCNT",
1373 "FISTA0", "CSAWA0", "PISTA0", "SHOTA0", "SGN2A0", "MGUNA0", "LAUNA0",
1374 "PLASA0", "BFUGA0", "GUN2A0"
1375 };
1376 stone = R_gl_loadimage("STONE");
1377 stone2 = R_gl_loadimage("STONE2");
1378 keys[0] = R_gl_loadimage("KEYRA0");
1379 keys[1] = R_gl_loadimage("KEYGA0");
1380 keys[2] = R_gl_loadimage("KEYBA0");
1381 for (i = 0; i < 22; i++) {
1382 sth[i] = R_gl_loadimage(mnm[i]);
1384 strcpy(s, "STBF_*");
1385 for (i = '!'; i < 160; i++) {
1386 s[5] = i;
1387 bfh[i - '!'] = R_gl_getimage(F_findres(s));
1389 for (i = '!'; i < 160; i++) {
1390 sprintf(s, "STCFN%03d", i);
1391 sfh[i - '!'] = R_gl_getimage(F_findres(s));
1393 strcpy(s, "WINUM*");
1394 for (i = '0'; i <= '9'; i++) {
1395 s[5] = i;
1396 bfh[i - '!'] = R_gl_loadimage(s);
1398 bfh[':' - '!'] = R_gl_loadimage("WICOLON");
1399 // menu
1400 msklh[0] = R_gl_loadimage("M_SKULL1");
1401 msklh[1] = R_gl_loadimage("M_SKULL2");
1402 mbarl = R_gl_loadimage("M_THERML");
1403 mbarm = R_gl_loadimage("M_THERMM");
1404 mbarr = R_gl_loadimage("M_THERMR");
1405 mbaro = R_gl_loadimage("M_THERMO");
1406 mslotl = R_gl_loadimage("M_LSLEFT");
1407 mslotm = R_gl_loadimage("M_LSCNTR");
1408 mslotr = R_gl_loadimage("M_LSRGHT");
1409 // walls
1410 for (i = 1; i < ANIT; i++) {
1411 for (j = 0; anm[i - 1][j]; j++) {
1412 anip[i][j] = R_gl_loadimage(anm[i - 1][j]);
1414 for(; j < 5; j++) {
1415 anip[i][j] = (image) {
1416 .w = 8,
1417 .h = 8,
1418 .res = -1,
1419 };
1424 void R_init (void) {
1425 Uint32 flags = SDL_OPENGL;
1426 if (fullscreen) {
1427 flags = flags | SDL_FULLSCREEN;
1429 if (SCRW <= 0 || SCRH <= 0) {
1430 ERR_failinit("Invalid screen size %ix%i\n", SCRW, SCRH);
1432 if (surf == NULL) {
1433 R_init_playpal(); // only onece
1435 surf = SDL_SetVideoMode(SCRW, SCRH, 0, flags);
1436 if (surf == NULL) {
1437 ERR_failinit("Unable to set video mode: %s\n", SDL_GetError());
1439 R_alloc();
1442 void R_done (void) {
1443 // do nothing
1446 void R_setgamma (int g) {
1447 gamma = g < 0 ? 0 : (g > 4 ? 4 : g);
1450 int R_getgamma (void) {
1451 return gamma;
1454 void R_toggle_fullscreen (void) {
1455 fullscreen = !fullscreen;
1456 if (surf) {
1457 R_init(); // recreate window
1461 void R_get_name (int n, char s[8]) {
1462 assert(n >= 0 && n < 256);
1463 if (walp[n].res == -1) {
1464 memset(s, 0, 8);
1465 } else if (walp[n].res == -2) {
1466 memcpy(s, "_WATER_", 8);
1467 s[7] = '0' + walp[n].id - 1;
1468 } else if (walani[n] > 0) {
1469 memcpy(s, anm[walani[n] - 1][0], 8);
1470 } else {
1471 F_getresname(s, walp[n].res & 0x7FFF);
1475 static short getani (char n[8]) {
1476 short i = 0;
1477 while (i < ANIT && strncasecmp(n, anm[i][0], 8) != 0) {
1478 i++;
1480 return i < ANIT ? i + 1 : 0;
1483 int R_get_special_id (int n) {
1484 assert(n >= 0 && n <= 256);
1485 return walp[n].res == -2 ? walp[n].id : -1;
1488 void R_begin_load (void) {
1489 int i;
1490 for (i = 0; i < 256; i++) {
1491 if (walp[i].id != 0 && walp[i].res >= 0 && walani[i] == 0) {
1492 R_gl_free_image(&walp[i]);
1494 memset(&walp[i], 0, sizeof(image));
1495 walp[i].res = -1;
1496 walswp[i] = i;
1497 walani[i] = 0;
1499 memset(anic, 0, sizeof(anic));
1500 max_wall_width = 0;
1501 max_wall_height = 0;
1502 max_textures = 1;
1505 void R_load (char s[8], int f) {
1506 assert(max_textures < 256);
1507 if (!s[0]) {
1508 walp[max_textures] = (image) {
1509 .id = 0,
1510 .x = 0,
1511 .y = 0,
1512 .w = 0,
1513 .h = 0,
1514 .res = -1,
1515 };
1516 } else if (strncasecmp(s, "_WATER_", 7) == 0) {
1517 walp[max_textures] = (image) {
1518 .id = s[7] - '0' + 1,
1519 .x = 0,
1520 .y = 0,
1521 .w = 8,
1522 .h = 8,
1523 .res = -2,
1524 };
1525 } else {
1526 walp[max_textures] = R_gl_loadimage(s);
1527 if (f) {
1528 walp[max_textures].res |= 0x8000;
1530 if (s[0] == 'S' && s[1] == 'W' && s[4] == '_') {
1531 walswp[max_textures] = 0;
1533 walani[max_textures] = getani(s);
1535 max_wall_width = max(max_wall_width, walp[max_textures].w);
1536 max_wall_height = max(max_wall_height, walp[max_textures].h);
1537 max_textures++;
1540 void R_end_load (void) {
1541 int i, j, k, g;
1542 char s[8];
1543 j = max_textures;
1544 for (i = 1; i < 256 && j < 256; i++) {
1545 if (walswp[i] == 0) {
1546 R_get_name(i, s);
1547 s[5] ^= 1;
1548 g = F_getresid(s) | (walp[i].res & 0x8000);
1549 k = 1;
1550 while (k < 256 && walp[k].res != g) {
1551 k += 1;
1553 if (k >= 256) {
1554 k = j;
1555 j += 1;
1556 walp[k] = R_gl_getimage(g);
1557 walf[k] = g & 0x8000 ? 1 : 0;
1559 walswp[i] = k;
1560 walswp[k] = i;
1565 void R_loadsky (int sky) {
1566 char s[6];
1567 logo("R_loadsky(%i)\n", sky);
1568 strcpy(s, "RSKYx");
1569 s[4] = '0' + sky;
1570 R_gl_free_image(&horiz);
1571 horiz = R_gl_loadimage(s);