1 //----------------------------------------------------------------------------
2 // EDGE 2D DRAWING STUFF
3 //----------------------------------------------------------------------------
4 //
5 // Copyright (c) 1999-2009 The EDGE Team.
6 //
7 // This program is free software; you can redistribute it and/or
8 // modify it under the terms of the GNU General Public License
9 // as published by the Free Software Foundation; either version 2
10 // of the License, or (at your option) any later version.
11 //
12 // This program is distributed in the hope that it will be useful,
13 // but WITHOUT ANY WARRANTY; without even the implied warranty of
14 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 // GNU General Public License for more details.
16 //
17 //----------------------------------------------------------------------------
18
19 #include "i_defs.h"
20 #include "i_defs_gl.h"
21
22 #include "ddf/font.h"
23
24 #include "g_game.h"
25 #include "r_misc.h"
26 #include "r_gldefs.h"
27 #include "r_units.h"
28 #include "r_colormap.h"
29 #include "hu_draw.h"
30 #include "r_modes.h"
31 #include "r_image.h"
32 #include "r_misc.h" // R_Render
33
34
35 #define DUMMY_WIDTH(font) (4)
36
37 #define HU_CHAR(ch) (islower(ch) ? toupper(ch) : (ch))
38 #define HU_INDEX(c) ((unsigned char) HU_CHAR(c))
39
40 static font_c *default_font;
41
42
43 float pixel_aspect = 1.0f;
44
45
46 // current state
47 static float cur_coord_W;
48 static float cur_coord_H;
49
50 static font_c *cur_font;
51 static rgbcol_t cur_color;
52
53 static float cur_scale, cur_alpha;
54 static int cur_x_align, cur_y_align;
55
56 static float margin_X;
57 static float margin_Y;
58 static float margin_W;
59 static float margin_H;
60
61 #define COORD_X(x) (margin_X + (x) * margin_W / cur_coord_W)
62 #define COORD_Y(y) (margin_Y - (y) * margin_H / cur_coord_H)
63
64 #define VERT_SPACING 2.0f
65
66
HUD_SetCoordSys(int width,int height)67 void HUD_SetCoordSys(int width, int height)
68 {
69 cur_coord_W = width;
70 cur_coord_H = height;
71 }
72
HUD_SetFont(font_c * font)73 void HUD_SetFont(font_c *font)
74 {
75 cur_font = font ? font : default_font;
76 }
77
HUD_SetScale(float scale)78 void HUD_SetScale(float scale)
79 {
80 cur_scale = scale;
81 }
82
HUD_SetTextColor(rgbcol_t color)83 void HUD_SetTextColor(rgbcol_t color)
84 {
85 cur_color = color;
86 }
87
HUD_SetAlpha(float alpha)88 void HUD_SetAlpha(float alpha)
89 {
90 cur_alpha = alpha;
91 }
92
HUD_SetAlignment(int xa,int ya)93 void HUD_SetAlignment(int xa, int ya)
94 {
95 cur_x_align = xa;
96 cur_y_align = ya;
97 }
98
99
HUD_Reset()100 void HUD_Reset()
101 {
102 HUD_SetCoordSys(320, 200);
103
104 cur_font = default_font;
105 cur_color = RGB_NO_VALUE;
106 cur_scale = 1.0f;
107 cur_alpha = 1.0f;
108 cur_x_align = cur_y_align = -1;
109 }
110
111
HUD_FrameSetup(void)112 void HUD_FrameSetup(void)
113 {
114 if (! default_font)
115 {
116 // FIXME: get default font from DDF gamedef
117 fontdef_c *DEF = fontdefs.Lookup("DOOM");
118 SYS_ASSERT(DEF);
119
120 default_font = hu_fonts.Lookup(DEF);
121 SYS_ASSERT(default_font);
122 }
123
124 HUD_Reset();
125
126 // determine pixel_aspect
127 float aspect = CLAMP(0.2, r_aspect.f, 5.0);
128
129 if (FULLSCREEN)
130 {
131 pixel_aspect = aspect * SCREENHEIGHT / (float)SCREENWIDTH;
132 }
133 else
134 {
135 int width, height;
136
137 I_GetDesktopSize(&width, &height);
138
139 pixel_aspect = aspect * height / (float)width;
140 }
141
142 // setup letterboxing for wide screens (etc)
143 margin_H = SCREENHEIGHT;
144
145 margin_W = margin_H * DOOM_ASPECT * (DOOM_PIXEL_ASPECT / pixel_aspect);
146
147 if (margin_W > SCREENWIDTH)
148 {
149 margin_H *= (float)SCREENWIDTH / margin_W;
150 margin_W = SCREENWIDTH;
151 }
152
153 margin_X = (SCREENWIDTH - margin_W) / 2.0;
154 margin_Y = (SCREENHEIGHT + margin_H) / 2.0;
155 }
156
157
158 #define MAX_SCISSOR_STACK 10
159
160 static int scissor_stack[MAX_SCISSOR_STACK][4];
161 static int sci_stack_top = 0;
162
163
HUD_PushScissor(float x1,float y1,float x2,float y2,bool expand)164 void HUD_PushScissor(float x1, float y1, float x2, float y2, bool expand)
165 {
166 SYS_ASSERT(sci_stack_top < MAX_SCISSOR_STACK);
167
168 // expand rendered view to cover whole screen
169 if (expand && x1 < 1 && x2 > cur_coord_W-1)
170 {
171 x1 = 0;
172 x2 = SCREENWIDTH;
173 }
174 else
175 {
176 x1 = COORD_X(x1);
177 x2 = COORD_X(x2);
178 }
179
180 std::swap(y1, y2);
181
182 y1 = COORD_Y(y1);
183 y2 = COORD_Y(y2);
184
185 int sx1 = I_ROUND(x1); int sy1 = I_ROUND(y1);
186 int sx2 = I_ROUND(x2); int sy2 = I_ROUND(y2);
187
188 if (sci_stack_top == 0)
189 {
190 glEnable(GL_SCISSOR_TEST);
191
192 sx1 = MAX(sx1, 0);
193 sy1 = MAX(sy1, 0);
194
195 sx2 = MIN(sx2, SCREENWIDTH);
196 sy2 = MIN(sy2, SCREENHEIGHT);
197 }
198 else
199 {
200 // clip to previous scissor
201 int *xy = scissor_stack[sci_stack_top-1];
202
203 sx1 = MAX(sx1, xy[0]);
204 sy1 = MAX(sy1, xy[1]);
205
206 sx2 = MIN(sx2, xy[2]);
207 sy2 = MIN(sy2, xy[3]);
208 }
209
210 SYS_ASSERT(sx2 >= sx1);
211 SYS_ASSERT(sy2 >= sy1);
212
213 glScissor(sx1, sy1, sx2 - sx1, sy2 - sy1);
214
215 // push current scissor
216 int *xy = scissor_stack[sci_stack_top];
217
218 xy[0] = sx1; xy[1] = sy1;
219 xy[2] = sx2; xy[3] = sy2;
220
221 sci_stack_top++;
222 }
223
224
HUD_PopScissor()225 void HUD_PopScissor()
226 {
227 SYS_ASSERT(sci_stack_top > 0);
228
229 sci_stack_top--;
230
231 if (sci_stack_top == 0)
232 {
233 glDisable(GL_SCISSOR_TEST);
234 }
235 else
236 {
237 // restore previous scissor
238 int *xy = scissor_stack[sci_stack_top];
239
240 glScissor(xy[0], xy[1], xy[2]-xy[0], xy[3]-xy[1]);
241 }
242 }
243
244
HUD_ScissorTest(float x1,float y1,float x2,float y2)245 bool HUD_ScissorTest(float x1, float y1, float x2, float y2)
246 {
247 if (sci_stack_top == 0)
248 return true;
249
250 if (x1 > x2) std::swap(x1, x2);
251 if (y1 < y2) std::swap(y1, y2);
252
253 x1 = COORD_X(x1); y1 = COORD_Y(y1);
254 x2 = COORD_X(x2); y2 = COORD_Y(y2);
255
256 int *xy = scissor_stack[sci_stack_top-1];
257
258 return ! (x2 < xy[0] || x1 > xy[2] || y2 < xy[1] || y1 > xy[3]);
259 }
260
261
262 //----------------------------------------------------------------------------
263
HUD_RawImage(float hx1,float hy1,float hx2,float hy2,const image_c * image,float tx1,float ty1,float tx2,float ty2,float alpha,rgbcol_t text_col,const colourmap_c * palremap)264 void HUD_RawImage(float hx1, float hy1, float hx2, float hy2,
265 const image_c *image,
266 float tx1, float ty1, float tx2, float ty2,
267 float alpha, rgbcol_t text_col,
268 const colourmap_c *palremap)
269 {
270 int x1 = I_ROUND(hx1);
271 int y1 = I_ROUND(hy1);
272 int x2 = I_ROUND(hx2+0.25f);
273 int y2 = I_ROUND(hy2+0.25f);
274
275 if (x1 >= x2 || y1 >= y2)
276 return;
277
278 if (x2 < 0 || x1 > SCREENWIDTH ||
279 y2 < 0 || y1 > SCREENHEIGHT)
280 return;
281
282 float r = 1.0f, g = 1.0f, b = 1.0f;
283
284 if (text_col != RGB_NO_VALUE)
285 {
286 r = RGB_RED(text_col) / 255.0;
287 g = RGB_GRN(text_col) / 255.0;
288 b = RGB_BLU(text_col) / 255.0;
289
290 palremap = font_whiten_map;
291 }
292
293 GLuint tex_id = W_ImageCache(image, true, palremap);
294
295 glEnable(GL_TEXTURE_2D);
296 glBindTexture(GL_TEXTURE_2D, tex_id);
297
298 if (alpha >= 0.99f && image->opacity == OPAC_Solid)
299 glDisable(GL_ALPHA_TEST);
300 else
301 {
302 glEnable(GL_ALPHA_TEST);
303
304 if (! (alpha < 0.11f || image->opacity == OPAC_Complex))
305 glAlphaFunc(GL_GREATER, alpha * 0.66f);
306 }
307
308 if (image->opacity == OPAC_Complex || alpha < 0.99f)
309 glEnable(GL_BLEND);
310
311 glColor4f(r, g, b, alpha);
312
313 glBegin(GL_QUADS);
314
315 glTexCoord2f(tx1, ty1);
316 glVertex2i(x1, y1);
317
318 glTexCoord2f(tx2, ty1);
319 glVertex2i(x2, y1);
320
321 glTexCoord2f(tx2, ty2);
322 glVertex2i(x2, y2);
323
324 glTexCoord2f(tx1, ty2);
325 glVertex2i(x1, y2);
326
327 glEnd();
328
329
330 glDisable(GL_TEXTURE_2D);
331 glDisable(GL_ALPHA_TEST);
332 glDisable(GL_BLEND);
333
334 glAlphaFunc(GL_GREATER, 0);
335 }
336
337
HUD_StretchImage(float x,float y,float w,float h,const image_c * img)338 void HUD_StretchImage(float x, float y, float w, float h, const image_c *img)
339 {
340 if (cur_x_align >= 0)
341 x -= w / (cur_x_align == 0 ? 2.0f : 1.0f);
342
343 if (cur_y_align >= 0)
344 y -= h / (cur_y_align == 0 ? 2.0f : 1.0f);
345
346 x -= IM_OFFSETX(img);
347 y -= IM_OFFSETY(img);
348
349 float x1 = COORD_X(x);
350 float x2 = COORD_X(x+w);
351
352 float y1 = COORD_Y(y+h);
353 float y2 = COORD_Y(y);
354
355 HUD_RawImage(x1, y1, x2, y2, img, 0, 0, IM_RIGHT(img), IM_TOP(img), cur_alpha);
356 }
357
358
HUD_DrawImage(float x,float y,const image_c * img)359 void HUD_DrawImage(float x, float y, const image_c *img)
360 {
361 float w = IM_WIDTH(img) * cur_scale;
362 float h = IM_HEIGHT(img) * cur_scale;
363
364 HUD_StretchImage(x, y, w, h, img);
365 }
366
367
HUD_TileImage(float x,float y,float w,float h,const image_c * img,float offset_x,float offset_y)368 void HUD_TileImage(float x, float y, float w, float h, const image_c *img,
369 float offset_x, float offset_y)
370 {
371 if (cur_x_align >= 0)
372 x -= w / (cur_x_align == 0 ? 2.0f : 1.0f);
373
374 if (cur_y_align >= 0)
375 y -= h / (cur_y_align == 0 ? 2.0f : 1.0f);
376
377 offset_x /= w;
378 offset_y /= -h;
379
380 float tx_scale = w / IM_TOTAL_WIDTH(img) / cur_scale;
381 float ty_scale = h / IM_TOTAL_HEIGHT(img) / cur_scale;
382
383 float x1 = COORD_X(x);
384 float x2 = COORD_X(x+w);
385
386 float y1 = COORD_Y(y+h);
387 float y2 = COORD_Y(y);
388
389 HUD_RawImage(x1, y1, x2, y2, img,
390 (offset_x) * tx_scale,
391 (offset_y) * ty_scale,
392 (offset_x + 1) * tx_scale,
393 (offset_y + 1) * ty_scale,
394 cur_alpha);
395 }
396
397
HUD_SolidBox(float x1,float y1,float x2,float y2,rgbcol_t col)398 void HUD_SolidBox(float x1, float y1, float x2, float y2, rgbcol_t col)
399 {
400 // expand to cover wide screens
401 if (x1 < 1 && x2 > cur_coord_W-1 && y1 < 1 && y2 > cur_coord_H-1)
402 {
403 x1 = 0; x2 = SCREENWIDTH;
404 y1 = 0; y2 = SCREENHEIGHT;
405 }
406 else
407 {
408 std::swap(y1, y2);
409
410 x1 = COORD_X(x1); y1 = COORD_Y(y1);
411 x2 = COORD_X(x2); y2 = COORD_Y(y2);
412 }
413
414 if (cur_alpha < 0.99f)
415 glEnable(GL_BLEND);
416
417 glColor4f(RGB_RED(col)/255.0, RGB_GRN(col)/255.0, RGB_BLU(col)/255.0, cur_alpha);
418
419 glBegin(GL_QUADS);
420
421 glVertex2f(x1, y1);
422 glVertex2f(x1, y2);
423 glVertex2f(x2, y2);
424 glVertex2f(x2, y1);
425
426 glEnd();
427 glDisable(GL_BLEND);
428 }
429
430
HUD_SolidLine(float x1,float y1,float x2,float y2,rgbcol_t col,bool thick,bool smooth,float dx,float dy)431 void HUD_SolidLine(float x1, float y1, float x2, float y2, rgbcol_t col,
432 bool thick, bool smooth, float dx, float dy)
433 {
434 x1 = COORD_X(x1); y1 = COORD_Y(y1);
435 x2 = COORD_X(x2); y2 = COORD_Y(y2);
436
437 dx = COORD_X(dx) - COORD_X(0);
438 dy = COORD_Y( 0) - COORD_Y(dy);
439
440 if (thick)
441 glLineWidth(1.5f);
442
443 if (smooth)
444 glEnable(GL_LINE_SMOOTH);
445
446 if (smooth || cur_alpha < 0.99f)
447 glEnable(GL_BLEND);
448
449 glColor4f(RGB_RED(col)/255.0, RGB_GRN(col)/255.0, RGB_BLU(col)/255.0, cur_alpha);
450
451 glBegin(GL_LINES);
452
453 glVertex2i((int)x1 + (int)dx, (int)y1 + (int)dy);
454 glVertex2i((int)x2 + (int)dx, (int)y2 + (int)dy);
455
456 glEnd();
457
458 glDisable(GL_BLEND);
459 glDisable(GL_LINE_SMOOTH);
460 glLineWidth(1.0f);
461 }
462
463
HUD_ThinBox(float x1,float y1,float x2,float y2,rgbcol_t col)464 void HUD_ThinBox(float x1, float y1, float x2, float y2, rgbcol_t col)
465 {
466 std::swap(y1, y2);
467
468 x1 = COORD_X(x1); y1 = COORD_Y(y1);
469 x2 = COORD_X(x2); y2 = COORD_Y(y2);
470
471 if (cur_alpha < 0.99f)
472 glEnable(GL_BLEND);
473
474 glColor4f(RGB_RED(col)/255.0, RGB_GRN(col)/255.0, RGB_BLU(col)/255.0, cur_alpha);
475
476 glBegin(GL_QUADS);
477 glVertex2f(x1, y1); glVertex2f(x1, y2);
478 glVertex2f(x1+2, y2); glVertex2f(x1+2, y1);
479 glEnd();
480
481 glBegin(GL_QUADS);
482 glVertex2f(x2-2, y1); glVertex2f(x2-2, y2);
483 glVertex2f(x2, y2); glVertex2f(x2, y1);
484 glEnd();
485
486 glBegin(GL_QUADS);
487 glVertex2f(x1+2, y1); glVertex2f(x1+2, y1+2);
488 glVertex2f(x2-2, y1+2); glVertex2f(x2-2, y1);
489 glEnd();
490
491 glBegin(GL_QUADS);
492 glVertex2f(x1+2, y2-2); glVertex2f(x1+2, y2);
493 glVertex2f(x2-2, y2); glVertex2f(x2-2, y2-2);
494 glEnd();
495
496 glDisable(GL_BLEND);
497 }
498
499
HUD_GradientBox(float x1,float y1,float x2,float y2,rgbcol_t * cols)500 void HUD_GradientBox(float x1, float y1, float x2, float y2, rgbcol_t *cols)
501 {
502 std::swap(y1, y2);
503
504 x1 = COORD_X(x1); y1 = COORD_Y(y1);
505 x2 = COORD_X(x2); y2 = COORD_Y(y2);
506
507 if (cur_alpha < 0.99f)
508 glEnable(GL_BLEND);
509
510 glBegin(GL_QUADS);
511
512 glColor4f(RGB_RED(cols[1])/255.0, RGB_GRN(cols[1])/255.0,
513 RGB_BLU(cols[1])/255.0, cur_alpha);
514 glVertex2f(x1, y1);
515
516 glColor4f(RGB_RED(cols[0])/255.0, RGB_GRN(cols[0])/255.0,
517 RGB_BLU(cols[0])/255.0, cur_alpha);
518 glVertex2f(x1, y2);
519
520 glColor4f(RGB_RED(cols[2])/255.0, RGB_GRN(cols[2])/255.0,
521 RGB_BLU(cols[2])/255.0, cur_alpha);
522 glVertex2f(x2, y2);
523
524 glColor4f(RGB_RED(cols[3])/255.0, RGB_GRN(cols[3])/255.0,
525 RGB_BLU(cols[3])/255.0, cur_alpha);
526 glVertex2f(x2, y1);
527
528 glEnd();
529 glDisable(GL_BLEND);
530 }
531
532
HUD_FontWidth(void)533 float HUD_FontWidth(void)
534 {
535 return cur_scale * cur_font->NominalWidth();
536 }
537
HUD_FontHeight(void)538 float HUD_FontHeight(void)
539 {
540 return cur_scale * cur_font->NominalHeight();
541 }
542
543
HUD_StringWidth(const char * str)544 float HUD_StringWidth(const char *str)
545 {
546 return cur_scale * cur_font->StringWidth(str);
547 }
548
HUD_StringHeight(const char * str)549 float HUD_StringHeight(const char *str)
550 {
551 int lines = cur_font->StringLines(str);
552
553 return lines * HUD_FontHeight() + (lines - 1) * VERT_SPACING;
554 }
555
556
HUD_DrawChar(float left_x,float top_y,const image_c * img)557 void HUD_DrawChar(float left_x, float top_y, const image_c *img)
558 {
559 float sc_x = cur_scale; // TODO * aspect;
560 float sc_y = cur_scale;
561
562 float x = left_x - IM_OFFSETX(img) * sc_x;
563 float y = top_y - IM_OFFSETY(img) * sc_y;
564
565 float w = IM_WIDTH(img) * sc_x;
566 float h = IM_HEIGHT(img) * sc_y;
567
568 float x1 = COORD_X(x);
569 float x2 = COORD_X(x+w);
570
571 float y1 = COORD_Y(y+h);
572 float y2 = COORD_Y(y);
573
574 HUD_RawImage(x1, y1, x2, y2, img, 0, 0, IM_RIGHT(img), IM_TOP(img),
575 cur_alpha, cur_color);
576 }
577
578
579 //
580 // Write a string using the current font
581 //
HUD_DrawText(float x,float y,const char * str)582 void HUD_DrawText(float x, float y, const char *str)
583 {
584 SYS_ASSERT(cur_font);
585
586 float cy = y;
587
588 if (cur_y_align >= 0)
589 {
590 float total_h = HUD_StringHeight(str);
591
592 if (cur_y_align == 0)
593 total_h /= 2.0f;
594
595 cy -= total_h;
596 }
597
598 // handle each line
599 while (*str)
600 {
601 // get the length of the line
602 int len = 0;
603 while (str[len] && str[len] != '\n')
604 len++;
605
606 float cx = x;
607 float total_w = 0;
608
609 for (int i = 0; i < len; i++)
610 total_w += cur_font->CharWidth(str[i]) * cur_scale;
611
612 if (cur_x_align >= 0)
613 {
614 if (cur_x_align == 0)
615 total_w /= 2.0f;
616
617 cx -= total_w;
618 }
619
620 for (int k = 0; k < len; k++)
621 {
622 char ch = str[k];
623
624 const image_c *img = cur_font->CharImage(ch);
625
626 if (img)
627 HUD_DrawChar(cx, cy, img);
628
629 cx += cur_font->CharWidth(ch) * cur_scale;
630 }
631
632 if (str[len] == 0)
633 break;
634
635 str += (len + 1);
636 cy += HUD_FontHeight() + VERT_SPACING;
637 }
638 }
639
640
HUD_RenderWorld(float x1,float y1,float x2,float y2,mobj_t * camera)641 void HUD_RenderWorld(float x1, float y1, float x2, float y2, mobj_t *camera)
642 {
643 HUD_PushScissor(x1, y1, x2, y2, true);
644
645 int *xy = scissor_stack[sci_stack_top-1];
646
647 bool full_height = (y2 - y1) > cur_coord_H * 0.95;
648
649 float width = COORD_X(x2) - COORD_X(x1);
650 float expand_w = (xy[2] - xy[0]) / width;
651
652 R_Render(xy[0], xy[1], xy[2]-xy[0], xy[3]-xy[1],
653 camera, full_height, expand_w);
654
655 HUD_PopScissor();
656 }
657
658
HUD_GetCastPosition(float * x,float * y,float * scale_x,float * scale_y)659 void HUD_GetCastPosition(float *x, float *y, float *scale_x, float *scale_y)
660 {
661 *x = COORD_X(160);
662 *y = COORD_Y(170);
663
664 *scale_y = margin_H / cur_coord_H;
665 *scale_x = *scale_y / pixel_aspect;
666 }
667
668 //--- editor settings ---
669 // vi:ts=4:sw=4:noexpandtab
670