1 /*
2 ** v_draw.cpp
3 ** Draw patches and blocks to a canvas
4 **
5 **---------------------------------------------------------------------------
6 ** Copyright 1998-2008 Randy Heit
7 ** All rights reserved.
8 **
9 ** Redistribution and use in source and binary forms, with or without
10 ** modification, are permitted provided that the following conditions
11 ** are met:
12 **
13 ** 1. Redistributions of source code must retain the above copyright
14 ** notice, this list of conditions and the following disclaimer.
15 ** 2. Redistributions in binary form must reproduce the above copyright
16 ** notice, this list of conditions and the following disclaimer in the
17 ** documentation and/or other materials provided with the distribution.
18 ** 3. The name of the author may not be used to endorse or promote products
19 ** derived from this software without specific prior written permission.
20 **
21 ** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
22 ** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
23 ** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
24 ** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
25 ** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
26 ** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27 ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28 ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29 ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
30 ** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 **---------------------------------------------------------------------------
32 **
33 */
34
35 // #define NO_SWRENDER // set this if you want to exclude the software renderer. Without software renderer the base implementations of DrawTextureV and FillSimplePoly need to be disabled because they depend on it.
36
37 #include <stdio.h>
38 #include <stdarg.h>
39
40 #include "doomtype.h"
41 #include "v_video.h"
42 #include "m_swap.h"
43 #include "r_defs.h"
44 #include "r_utility.h"
45 #ifndef NO_SWRENDER
46 #include "r_draw.h"
47 #include "r_main.h"
48 #include "r_things.h"
49 #endif
50 #include "r_data/r_translate.h"
51 #include "doomstat.h"
52 #include "v_palette.h"
53 #include "gi.h"
54 #include "g_level.h"
55 #include "st_stuff.h"
56 #include "sbar.h"
57
58 #include "i_system.h"
59 #include "i_video.h"
60 #include "templates.h"
61 #include "d_net.h"
62 #include "colormatcher.h"
63 #include "r_data/colormaps.h"
64
65 // [RH] Stretch values to make a 320x200 image best fit the screen
66 // without using fractional steppings
67 int CleanXfac, CleanYfac;
68
69 // [RH] Effective screen sizes that the above scale values give you
70 int CleanWidth, CleanHeight;
71
72 // Above minus 1 (or 1, if they are already 1)
73 int CleanXfac_1, CleanYfac_1, CleanWidth_1, CleanHeight_1;
74
75 // FillSimplePoly uses this
76 extern "C" short spanend[MAXHEIGHT];
77
78 CVAR (Bool, hud_scale, false, CVAR_ARCHIVE);
79
80 // For routines that take RGB colors, cache the previous lookup in case there
81 // are several repetitions with the same color.
82 static int LastPal = -1;
83 static uint32 LastRGB;
84
85
PalFromRGB(uint32 rgb)86 static int PalFromRGB(uint32 rgb)
87 {
88 if (LastPal >= 0 && LastRGB == rgb)
89 {
90 return LastPal;
91 }
92 // Quick check for black and white.
93 if (rgb == MAKEARGB(255,0,0,0))
94 {
95 LastPal = GPalette.BlackIndex;
96 }
97 else if (rgb == MAKEARGB(255,255,255,255))
98 {
99 LastPal = GPalette.WhiteIndex;
100 }
101 else
102 {
103 LastPal = ColorMatcher.Pick(RPART(rgb), GPART(rgb), BPART(rgb));
104 }
105 LastRGB = rgb;
106 return LastPal;
107 }
108
DrawTexture(FTexture * img,double x,double y,int tags_first,...)109 void STACK_ARGS DCanvas::DrawTexture (FTexture *img, double x, double y, int tags_first, ...)
110 {
111 va_list tags;
112 va_start(tags, tags_first);
113 DrawTextureV(img, x, y, tags_first, tags);
114 }
115
DrawTextureV(FTexture * img,double x,double y,uint32 tag,va_list tags)116 void STACK_ARGS DCanvas::DrawTextureV(FTexture *img, double x, double y, uint32 tag, va_list tags)
117 {
118 #ifndef NO_SWRENDER
119 FTexture::Span unmaskedSpan[2];
120 const FTexture::Span **spanptr, *spans;
121 static short bottomclipper[MAXWIDTH], topclipper[MAXWIDTH];
122
123 DrawParms parms;
124
125 if (!ParseDrawTextureTags(img, x, y, tag, tags, &parms, false))
126 {
127 return;
128 }
129
130 if (parms.masked)
131 {
132 spanptr = &spans;
133 }
134 else
135 {
136 spanptr = NULL;
137 }
138
139 if (APART(parms.colorOverlay) != 0)
140 {
141 // The software renderer cannot invert the source without inverting the overlay
142 // too. That means if the source is inverted, we need to do the reverse of what
143 // the invert overlay flag says to do.
144 INTBOOL invertoverlay = (parms.style.Flags & STYLEF_InvertOverlay);
145
146 if (parms.style.Flags & STYLEF_InvertSource)
147 {
148 invertoverlay = !invertoverlay;
149 }
150 if (invertoverlay)
151 {
152 parms.colorOverlay = PalEntry(parms.colorOverlay).InverseColor();
153 }
154 // Note that this overrides DTA_Translation in software, but not in hardware.
155 FDynamicColormap *colormap = GetSpecialLights(MAKERGB(255,255,255),
156 parms.colorOverlay & MAKEARGB(0,255,255,255), 0);
157 parms.translation = &colormap->Maps[(APART(parms.colorOverlay)*NUMCOLORMAPS/255)*256];
158 }
159
160 if (parms.translation != NULL)
161 {
162 dc_colormap = (lighttable_t *)parms.translation;
163 }
164 else
165 {
166 dc_colormap = identitymap;
167 }
168
169 fixedcolormap = dc_colormap;
170 ESPSResult mode = R_SetPatchStyle (parms.style, parms.alpha, 0, parms.fillcolor);
171
172 BYTE *destorgsave = dc_destorg;
173 dc_destorg = screen->GetBuffer();
174
175 double x0 = parms.x - parms.left * parms.destwidth / parms.texwidth;
176 double y0 = parms.y - parms.top * parms.destheight / parms.texheight;
177
178 if (mode != DontDraw)
179 {
180 const BYTE *pixels;
181 int stop4;
182
183 if (spanptr == NULL)
184 { // Create a single span for forced unmasked images
185 spans = unmaskedSpan;
186 unmaskedSpan[0].TopOffset = 0;
187 unmaskedSpan[0].Length = img->GetHeight();
188 unmaskedSpan[1].TopOffset = 0;
189 unmaskedSpan[1].Length = 0;
190 }
191
192 fixed_t centeryback = centeryfrac;
193 centeryfrac = 0;
194
195 sprtopscreen = FLOAT2FIXED(y0);
196 // There is not enough precision in the drawing routines to keep the full
197 // precision for y0. :(
198 sprtopscreen &= ~(FRACUNIT - 1);
199
200 double yscale = parms.destheight / img->GetHeight();
201 double iyscale = 1 / yscale;
202
203 spryscale = FLOAT2FIXED(yscale);
204 assert(spryscale > 2);
205 #if 0
206 // Fix precision errors that are noticeable at some resolutions
207 if ((y0 + parms.destheight) > (y0 + yscale * img->GetHeight()))
208 {
209 spryscale++;
210 }
211 #endif
212
213 sprflipvert = false;
214 //dc_iscale = FLOAT2FIXED(iyscale);
215 //dc_texturemid = FLOAT2FIXED((-y0) * iyscale);
216 //dc_iscale = 0xffffffffu / (unsigned)spryscale;
217 dc_iscale = DivScale32(1, spryscale);
218 dc_texturemid = FixedMul(-sprtopscreen, dc_iscale) + FixedMul(centeryfrac-FRACUNIT, dc_iscale);
219 fixed_t frac = 0;
220 double xiscale = img->GetWidth() / parms.destwidth;
221 double x2 = x0 + parms.destwidth;
222
223 if (bottomclipper[0] != parms.dclip)
224 {
225 clearbufshort(bottomclipper, screen->GetWidth(), (short)parms.dclip);
226 }
227 if (parms.uclip != 0)
228 {
229 if (topclipper[0] != parms.uclip)
230 {
231 clearbufshort(topclipper, screen->GetWidth(), (short)parms.uclip);
232 }
233 mceilingclip = topclipper;
234 }
235 else
236 {
237 mceilingclip = zeroarray;
238 }
239 mfloorclip = bottomclipper;
240
241 if (parms.flipX)
242 {
243 frac = (img->GetWidth() << FRACBITS) - 1;
244 xiscale = -xiscale;
245 }
246
247 if (parms.windowleft > 0 || parms.windowright < parms.texwidth)
248 {
249 double xscale = parms.destwidth / parms.texwidth;
250 x0 += parms.windowleft * xscale;
251 frac += FLOAT2FIXED(parms.windowleft);
252 x2 -= (parms.texwidth - parms.windowright) * xscale;
253 }
254 if (x0 < parms.lclip)
255 {
256 frac += FLOAT2FIXED((parms.lclip - x0) * xiscale);
257 x0 = parms.lclip;
258 }
259 if (x2 > parms.rclip)
260 {
261 x2 = parms.rclip;
262 }
263
264 // Drawing short output ought to fit in the data cache well enough
265 // if we draw one column at a time, so do that, since it's simpler.
266 if (parms.destheight < 32 || (parms.dclip - parms.uclip) < 32)
267 {
268 mode = DoDraw0;
269 }
270
271 dc_x = int(x0);
272 int x2_i = int(x2);
273 fixed_t xiscale_i = FLOAT2FIXED(xiscale);
274
275 if (mode == DoDraw0)
276 {
277 // One column at a time
278 stop4 = dc_x;
279 }
280 else // DoDraw1`
281 {
282 // Up to four columns at a time
283 stop4 = x2_i & ~3;
284 }
285
286 if (dc_x < x2_i)
287 {
288 while ((dc_x < stop4) && (dc_x & 3))
289 {
290 pixels = img->GetColumn(frac >> FRACBITS, spanptr);
291 R_DrawMaskedColumn(pixels, spans);
292 dc_x++;
293 frac += xiscale_i;
294 }
295
296 while (dc_x < stop4)
297 {
298 rt_initcols();
299 for (int zz = 4; zz; --zz)
300 {
301 pixels = img->GetColumn(frac >> FRACBITS, spanptr);
302 R_DrawMaskedColumnHoriz(pixels, spans);
303 dc_x++;
304 frac += xiscale_i;
305 }
306 rt_draw4cols(dc_x - 4);
307 }
308
309 while (dc_x < x2_i)
310 {
311 pixels = img->GetColumn(frac >> FRACBITS, spanptr);
312 R_DrawMaskedColumn(pixels, spans);
313 dc_x++;
314 frac += xiscale_i;
315 }
316 }
317 centeryfrac = centeryback;
318 }
319 R_FinishSetPatchStyle ();
320
321 dc_destorg = destorgsave;
322
323 if (ticdup != 0 && menuactive == MENU_Off)
324 {
325 NetUpdate();
326 }
327 #endif
328 }
329
ParseDrawTextureTags(FTexture * img,double x,double y,DWORD tag,va_list tags,DrawParms * parms,bool hw) const330 bool DCanvas::ParseDrawTextureTags (FTexture *img, double x, double y, DWORD tag, va_list tags, DrawParms *parms, bool hw) const
331 {
332 INTBOOL boolval;
333 int intval;
334 bool translationset = false;
335 bool virtBottom;
336 bool fillcolorset = false;
337
338 if (img == NULL || img->UseType == FTexture::TEX_Null)
339 {
340 va_end(tags);
341 return false;
342 }
343
344 // Do some sanity checks on the coordinates.
345 if (x < -16383 || x > 16383 || y < -16383 || y > 16383)
346 {
347 va_end(tags);
348 return false;
349 }
350
351 virtBottom = false;
352
353 parms->texwidth = img->GetScaledWidthDouble();
354 parms->texheight = img->GetScaledHeightDouble();
355
356 parms->windowleft = 0;
357 parms->windowright = parms->texwidth;
358 parms->dclip = this->GetHeight();
359 parms->uclip = 0;
360 parms->lclip = 0;
361 parms->rclip = this->GetWidth();
362 parms->destwidth = parms->windowright;
363 parms->destheight = parms->texheight;
364 parms->top = img->GetScaledTopOffset();
365 parms->left = img->GetScaledLeftOffset();
366 parms->alpha = FRACUNIT;
367 parms->fillcolor = -1;
368 parms->remap = NULL;
369 parms->translation = NULL;
370 parms->colorOverlay = 0;
371 parms->alphaChannel = false;
372 parms->flipX = false;
373 parms->shadowAlpha = 0;
374 parms->shadowColor = 0;
375 parms->virtWidth = this->GetWidth();
376 parms->virtHeight = this->GetHeight();
377 parms->keepratio = false;
378 parms->style.BlendOp = 255; // Dummy "not set" value
379 parms->masked = true;
380 parms->bilinear = false;
381 parms->specialcolormap = NULL;
382 parms->colormapstyle = NULL;
383
384 parms->x = x;
385 parms->y = y;
386
387 // Parse the tag list for attributes. (For floating point attributes,
388 // consider that the C ABI dictates that all floats be promoted to
389 // doubles when passed as function arguments.)
390 while (tag != TAG_DONE)
391 {
392 va_list *more_p;
393 DWORD data;
394
395 switch (tag)
396 {
397 case TAG_IGNORE:
398 default:
399 data = va_arg(tags, DWORD);
400 break;
401
402 case TAG_MORE:
403 more_p = va_arg(tags, va_list *);
404 va_end (tags);
405 #ifndef NO_VA_COPY
406 va_copy (tags, *more_p);
407 #else
408 tags = *more_p;
409 #endif
410 break;
411
412 case DTA_DestWidth:
413 parms->destwidth = va_arg(tags, int);
414 break;
415
416 case DTA_DestWidthF:
417 parms->destwidth = va_arg(tags, double);
418 break;
419
420 case DTA_DestHeight:
421 parms->destheight = va_arg(tags, int);
422 break;
423
424 case DTA_DestHeightF:
425 parms->destheight = va_arg(tags, double);
426 break;
427
428 case DTA_Clean:
429 boolval = va_arg(tags, INTBOOL);
430 if (boolval)
431 {
432 parms->x = (parms->x - 160.0) * CleanXfac + (Width * 0.5);
433 parms->y = (parms->y - 100.0) * CleanYfac + (Height * 0.5);
434 parms->destwidth = parms->texwidth * CleanXfac;
435 parms->destheight = parms->texheight * CleanYfac;
436 }
437 break;
438
439 case DTA_CleanNoMove:
440 boolval = va_arg(tags, INTBOOL);
441 if (boolval)
442 {
443 parms->destwidth = parms->texwidth * CleanXfac;
444 parms->destheight = parms->texheight * CleanYfac;
445 }
446 break;
447
448 case DTA_CleanNoMove_1:
449 boolval = va_arg(tags, INTBOOL);
450 if (boolval)
451 {
452 parms->destwidth = parms->texwidth * CleanXfac_1;
453 parms->destheight = parms->texheight * CleanYfac_1;
454 }
455 break;
456
457 case DTA_320x200:
458 boolval = va_arg(tags, INTBOOL);
459 if (boolval)
460 {
461 parms->virtWidth = 320;
462 parms->virtHeight = 200;
463 }
464 break;
465
466 case DTA_Bottom320x200:
467 boolval = va_arg(tags, INTBOOL);
468 if (boolval)
469 {
470 parms->virtWidth = 320;
471 parms->virtHeight = 200;
472 }
473 virtBottom = true;
474 break;
475
476 case DTA_HUDRules:
477 {
478 bool xright = parms->x < 0;
479 bool ybot = parms->y < 0;
480 intval = va_arg(tags, int);
481
482 if (hud_scale)
483 {
484 parms->x *= CleanXfac;
485 if (intval == HUD_HorizCenter)
486 parms->x += Width * 0.5;
487 else if (xright)
488 parms->x = Width + parms->x;
489 parms->y *= CleanYfac;
490 if (ybot)
491 parms->y = Height + parms->y;
492 parms->destwidth = parms->texwidth * CleanXfac;
493 parms->destheight = parms->texheight * CleanYfac;
494 }
495 else
496 {
497 if (intval == HUD_HorizCenter)
498 parms->x += Width * 0.5;
499 else if (xright)
500 parms->x = Width + parms->x;
501 if (ybot)
502 parms->y = Height + parms->y;
503 }
504 }
505 break;
506
507 case DTA_VirtualWidth:
508 parms->virtWidth = va_arg(tags, int);
509 break;
510
511 case DTA_VirtualWidthF:
512 parms->virtWidth = va_arg(tags, double);
513 break;
514
515 case DTA_VirtualHeight:
516 parms->virtHeight = va_arg(tags, int);
517 break;
518
519 case DTA_VirtualHeightF:
520 parms->virtHeight = va_arg(tags, double);
521 break;
522
523 case DTA_Fullscreen:
524 boolval = va_arg(tags, INTBOOL);
525 if (boolval)
526 {
527 parms->x = parms->y = 0;
528 parms->virtWidth = img->GetScaledWidthDouble();
529 parms->virtHeight = img->GetScaledHeightDouble();
530 }
531 break;
532
533 case DTA_Alpha:
534 parms->alpha = MIN<fixed_t>(FRACUNIT, va_arg (tags, fixed_t));
535 break;
536
537 case DTA_AlphaChannel:
538 parms->alphaChannel = va_arg(tags, INTBOOL);
539 break;
540
541 case DTA_FillColor:
542 parms->fillcolor = va_arg(tags, uint32);
543 fillcolorset = true;
544 break;
545
546 case DTA_Translation:
547 parms->remap = va_arg(tags, FRemapTable *);
548 if (parms->remap != NULL && parms->remap->Inactive)
549 { // If it's inactive, pretend we were passed NULL instead.
550 parms->remap = NULL;
551 }
552 break;
553
554 case DTA_ColorOverlay:
555 parms->colorOverlay = va_arg(tags, DWORD);
556 break;
557
558 case DTA_FlipX:
559 parms->flipX = va_arg(tags, INTBOOL);
560 break;
561
562 case DTA_TopOffset:
563 parms->top = va_arg(tags, int);
564 break;
565
566 case DTA_TopOffsetF:
567 parms->top = va_arg(tags, double);
568 break;
569
570 case DTA_LeftOffset:
571 parms->left = va_arg(tags, int);
572 break;
573
574 case DTA_LeftOffsetF:
575 parms->left = va_arg(tags, double);
576 break;
577
578 case DTA_CenterOffset:
579 if (va_arg(tags, int))
580 {
581 parms->left = parms->texwidth * 0.5;
582 parms->top = parms->texheight * 0.5;
583 }
584 break;
585
586 case DTA_CenterBottomOffset:
587 if (va_arg(tags, int))
588 {
589 parms->left = parms->texwidth * 0.5;
590 parms->top = parms->texheight;
591 }
592 break;
593
594 case DTA_WindowLeft:
595 parms->windowleft = va_arg(tags, int);
596 break;
597
598 case DTA_WindowLeftF:
599 parms->windowleft = va_arg(tags, double);
600 break;
601
602 case DTA_WindowRight:
603 parms->windowright = va_arg(tags, int);
604 break;
605
606 case DTA_WindowRightF:
607 parms->windowright = va_arg(tags, double);
608 break;
609
610 case DTA_ClipTop:
611 parms->uclip = va_arg(tags, int);
612 if (parms->uclip < 0)
613 {
614 parms->uclip = 0;
615 }
616 break;
617
618 case DTA_ClipBottom:
619 parms->dclip = va_arg(tags, int);
620 if (parms->dclip > this->GetHeight())
621 {
622 parms->dclip = this->GetHeight();
623 }
624 break;
625
626 case DTA_ClipLeft:
627 parms->lclip = va_arg(tags, int);
628 if (parms->lclip < 0)
629 {
630 parms->lclip = 0;
631 }
632 break;
633
634 case DTA_ClipRight:
635 parms->rclip = va_arg(tags, int);
636 if (parms->rclip > this->GetWidth())
637 {
638 parms->rclip = this->GetWidth();
639 }
640 break;
641
642 case DTA_ShadowAlpha:
643 parms->shadowAlpha = MIN<fixed_t>(FRACUNIT, va_arg (tags, fixed_t));
644 break;
645
646 case DTA_ShadowColor:
647 parms->shadowColor = va_arg(tags, int);
648 break;
649
650 case DTA_Shadow:
651 boolval = va_arg(tags, INTBOOL);
652 if (boolval)
653 {
654 parms->shadowAlpha = FRACUNIT/2;
655 parms->shadowColor = 0;
656 }
657 else
658 {
659 parms->shadowAlpha = 0;
660 }
661 break;
662
663 case DTA_Masked:
664 parms->masked = va_arg(tags, INTBOOL);
665 break;
666
667 case DTA_BilinearFilter:
668 parms->bilinear = va_arg(tags, INTBOOL);
669 break;
670
671 case DTA_KeepRatio:
672 // I think this is a terribly misleading name, since it actually turns
673 // *off* aspect ratio correction.
674 parms->keepratio = va_arg(tags, INTBOOL);
675 break;
676
677 case DTA_RenderStyle:
678 parms->style.AsDWORD = va_arg(tags, DWORD);
679 break;
680
681 case DTA_SpecialColormap:
682 parms->specialcolormap = va_arg(tags, FSpecialColormap *);
683 break;
684
685 case DTA_ColormapStyle:
686 parms->colormapstyle = va_arg(tags, FColormapStyle *);
687 break;
688 }
689 tag = va_arg(tags, DWORD);
690 }
691 va_end (tags);
692
693 if (parms->uclip >= parms->dclip || parms->lclip >= parms->rclip)
694 {
695 return false;
696 }
697
698 if (parms->virtWidth != Width || parms->virtHeight != Height)
699 {
700 VirtualToRealCoords(parms->x, parms->y, parms->destwidth, parms->destheight,
701 parms->virtWidth, parms->virtHeight, virtBottom, !parms->keepratio);
702 }
703
704 if (parms->destwidth <= 0 || parms->destheight <= 0)
705 {
706 return false;
707 }
708
709 if (parms->remap != NULL)
710 {
711 parms->translation = parms->remap->Remap;
712 }
713
714 if (parms->style.BlendOp == 255)
715 {
716 if (fillcolorset)
717 {
718 if (parms->alphaChannel)
719 {
720 parms->style = STYLE_Shaded;
721 }
722 else if (parms->alpha < FRACUNIT)
723 {
724 parms->style = STYLE_TranslucentStencil;
725 }
726 else
727 {
728 parms->style = STYLE_Stencil;
729 }
730 }
731 else if (parms->alpha < FRACUNIT)
732 {
733 parms->style = STYLE_Translucent;
734 }
735 else
736 {
737 parms->style = STYLE_Normal;
738 }
739 }
740 return true;
741 }
742
VirtualToRealCoords(double & x,double & y,double & w,double & h,double vwidth,double vheight,bool vbottom,bool handleaspect) const743 void DCanvas::VirtualToRealCoords(double &x, double &y, double &w, double &h,
744 double vwidth, double vheight, bool vbottom, bool handleaspect) const
745 {
746 int myratio = handleaspect ? CheckRatio (Width, Height) : 0;
747 double right = x + w;
748 double bottom = y + h;
749
750 if (myratio != 0 && myratio != 4)
751 { // The target surface is either 16:9 or 16:10, so expand the
752 // specified virtual size to avoid undesired stretching of the
753 // image. Does not handle non-4:3 virtual sizes. I'll worry about
754 // those if somebody expresses a desire to use them.
755 x = (x - vwidth * 0.5) * Width * 960 / (vwidth * BaseRatioSizes[myratio][0]) + Width * 0.5;
756 w = (right - vwidth * 0.5) * Width * 960 / (vwidth * BaseRatioSizes[myratio][0]) + Width * 0.5 - x;
757 }
758 else
759 {
760 x = x * Width / vwidth;
761 w = right * Width / vwidth - x;
762 }
763 if (myratio == 4)
764 { // The target surface is 5:4
765 y = (y - vheight * 0.5) * Height * 600 / (vheight * BaseRatioSizes[myratio][1]) + Height * 0.5;
766 h = (bottom - vheight * 0.5) * Height * 600 / (vheight * BaseRatioSizes[myratio][1]) + Height * 0.5 - y;
767 if (vbottom)
768 {
769 y += (Height - Height * BaseRatioSizes[myratio][3] / 48.0) * 0.5;
770 }
771 }
772 else
773 {
774 y = y * Height / vheight;
775 h = bottom * Height / vheight - y;
776 }
777 }
778
VirtualToRealCoordsFixed(fixed_t & x,fixed_t & y,fixed_t & w,fixed_t & h,int vwidth,int vheight,bool vbottom,bool handleaspect) const779 void DCanvas::VirtualToRealCoordsFixed(fixed_t &x, fixed_t &y, fixed_t &w, fixed_t &h,
780 int vwidth, int vheight, bool vbottom, bool handleaspect) const
781 {
782 double dx, dy, dw, dh;
783
784 dx = FIXED2FLOAT(x);
785 dy = FIXED2FLOAT(y);
786 dw = FIXED2FLOAT(w);
787 dh = FIXED2FLOAT(h);
788 VirtualToRealCoords(dx, dy, dw, dh, vwidth, vheight, vbottom, handleaspect);
789 x = FLOAT2FIXED(dx);
790 y = FLOAT2FIXED(dy);
791 w = FLOAT2FIXED(dw);
792 h = FLOAT2FIXED(dh);
793 }
794
VirtualToRealCoordsInt(int & x,int & y,int & w,int & h,int vwidth,int vheight,bool vbottom,bool handleaspect) const795 void DCanvas::VirtualToRealCoordsInt(int &x, int &y, int &w, int &h,
796 int vwidth, int vheight, bool vbottom, bool handleaspect) const
797 {
798 double dx, dy, dw, dh;
799
800 dx = x;
801 dy = y;
802 dw = w;
803 dh = h;
804 VirtualToRealCoords(dx, dy, dw, dh, vwidth, vheight, vbottom, handleaspect);
805 x = int(dx + 0.5);
806 y = int(dy + 0.5);
807 w = int(dx + dw + 0.5) - x;
808 h = int(dy + dh + 0.5) - y;
809 }
810
FillBorder(FTexture * img)811 void DCanvas::FillBorder (FTexture *img)
812 {
813 int myratio = CheckRatio (Width, Height);
814 if (myratio == 0)
815 { // This is a 4:3 display, so no border to show
816 return;
817 }
818 int bordtop, bordbottom, bordleft, bordright, bord;
819 if (myratio & 4)
820 { // Screen is taller than it is wide
821 bordleft = bordright = 0;
822 bord = Height - Height * BaseRatioSizes[myratio][3] / 48;
823 bordtop = bord / 2;
824 bordbottom = bord - bordtop;
825 }
826 else
827 { // Screen is wider than it is tall
828 bordtop = bordbottom = 0;
829 bord = Width - Width * BaseRatioSizes[myratio][3] / 48;
830 bordleft = bord / 2;
831 bordright = bord - bordleft;
832 }
833
834 if (img != NULL)
835 {
836 FlatFill (0, 0, Width, bordtop, img); // Top
837 FlatFill (0, bordtop, bordleft, Height - bordbottom, img); // Left
838 FlatFill (Width - bordright, bordtop, Width, Height - bordbottom, img); // Right
839 FlatFill (0, Height - bordbottom, Width, Height, img); // Bottom
840 }
841 else
842 {
843 Clear (0, 0, Width, bordtop, GPalette.BlackIndex, 0); // Top
844 Clear (0, bordtop, bordleft, Height - bordbottom, GPalette.BlackIndex, 0); // Left
845 Clear (Width - bordright, bordtop, Width, Height - bordbottom, GPalette.BlackIndex, 0); // Right
846 Clear (0, Height - bordbottom, Width, Height, GPalette.BlackIndex, 0); // Bottom
847 }
848 }
849
PUTTRANSDOT(int xx,int yy,int basecolor,int level)850 void DCanvas::PUTTRANSDOT (int xx, int yy, int basecolor, int level)
851 {
852 static int oldyy;
853 static int oldyyshifted;
854
855 #if 0
856 if(xx < 32)
857 cc += 7-(xx>>2);
858 else if(xx > (finit_width - 32))
859 cc += 7-((finit_width-xx) >> 2);
860 // if(cc==oldcc) //make sure that we don't double fade the corners.
861 // {
862 if(yy < 32)
863 cc += 7-(yy>>2);
864 else if(yy > (finit_height - 32))
865 cc += 7-((finit_height-yy) >> 2);
866 // }
867 if(cc > cm && cm != NULL)
868 {
869 cc = cm;
870 }
871 else if(cc > oldcc+6) // don't let the color escape from the fade table...
872 {
873 cc=oldcc+6;
874 }
875 #endif
876 if (yy == oldyy+1)
877 {
878 oldyy++;
879 oldyyshifted += GetPitch();
880 }
881 else if (yy == oldyy-1)
882 {
883 oldyy--;
884 oldyyshifted -= GetPitch();
885 }
886 else if (yy != oldyy)
887 {
888 oldyy = yy;
889 oldyyshifted = yy * GetPitch();
890 }
891
892 BYTE *spot = GetBuffer() + oldyyshifted + xx;
893 DWORD *bg2rgb = Col2RGB8[1+level];
894 DWORD *fg2rgb = Col2RGB8[63-level];
895 DWORD fg = fg2rgb[basecolor];
896 DWORD bg = bg2rgb[*spot];
897 bg = (fg+bg) | 0x1f07c1f;
898 *spot = RGB32k.All[bg&(bg>>15)];
899 }
900
DrawLine(int x0,int y0,int x1,int y1,int palColor,uint32 realcolor)901 void DCanvas::DrawLine(int x0, int y0, int x1, int y1, int palColor, uint32 realcolor)
902 //void DrawTransWuLine (int x0, int y0, int x1, int y1, BYTE palColor)
903 {
904 const int WeightingScale = 0;
905 const int WEIGHTBITS = 6;
906 const int WEIGHTSHIFT = 16-WEIGHTBITS;
907 const int NUMWEIGHTS = (1<<WEIGHTBITS);
908 const int WEIGHTMASK = (NUMWEIGHTS-1);
909
910 if (palColor < 0)
911 {
912 palColor = PalFromRGB(realcolor);
913 }
914
915 Lock();
916 int deltaX, deltaY, xDir;
917
918 if (y0 > y1)
919 {
920 int temp = y0; y0 = y1; y1 = temp;
921 temp = x0; x0 = x1; x1 = temp;
922 }
923
924 PUTTRANSDOT (x0, y0, palColor, 0);
925
926 if ((deltaX = x1 - x0) >= 0)
927 {
928 xDir = 1;
929 }
930 else
931 {
932 xDir = -1;
933 deltaX = -deltaX;
934 }
935
936 if ((deltaY = y1 - y0) == 0)
937 { // horizontal line
938 if (x0 > x1)
939 {
940 swapvalues (x0, x1);
941 }
942 memset (GetBuffer() + y0*GetPitch() + x0, palColor, deltaX+1);
943 }
944 else if (deltaX == 0)
945 { // vertical line
946 BYTE *spot = GetBuffer() + y0*GetPitch() + x0;
947 int pitch = GetPitch ();
948 do
949 {
950 *spot = palColor;
951 spot += pitch;
952 } while (--deltaY != 0);
953 }
954 else if (deltaX == deltaY)
955 { // diagonal line.
956 BYTE *spot = GetBuffer() + y0*GetPitch() + x0;
957 int advance = GetPitch() + xDir;
958 do
959 {
960 *spot = palColor;
961 spot += advance;
962 } while (--deltaY != 0);
963 }
964 else
965 {
966 // line is not horizontal, diagonal, or vertical
967 fixed_t errorAcc = 0;
968
969 if (deltaY > deltaX)
970 { // y-major line
971 fixed_t errorAdj = (((unsigned)deltaX << 16) / (unsigned)deltaY) & 0xffff;
972 if (xDir < 0)
973 {
974 if (WeightingScale == 0)
975 {
976 while (--deltaY)
977 {
978 errorAcc += errorAdj;
979 y0++;
980 int weighting = (errorAcc >> WEIGHTSHIFT) & WEIGHTMASK;
981 PUTTRANSDOT (x0 - (errorAcc >> 16), y0, palColor, weighting);
982 PUTTRANSDOT (x0 - (errorAcc >> 16) - 1, y0,
983 palColor, WEIGHTMASK - weighting);
984 }
985 }
986 else
987 {
988 while (--deltaY)
989 {
990 errorAcc += errorAdj;
991 y0++;
992 int weighting = ((errorAcc * WeightingScale) >> (WEIGHTSHIFT+8)) & WEIGHTMASK;
993 PUTTRANSDOT (x0 - (errorAcc >> 16), y0, palColor, weighting);
994 PUTTRANSDOT (x0 - (errorAcc >> 16) - 1, y0,
995 palColor, WEIGHTMASK - weighting);
996 }
997 }
998 }
999 else
1000 {
1001 if (WeightingScale == 0)
1002 {
1003 while (--deltaY)
1004 {
1005 errorAcc += errorAdj;
1006 y0++;
1007 int weighting = (errorAcc >> WEIGHTSHIFT) & WEIGHTMASK;
1008 PUTTRANSDOT (x0 + (errorAcc >> 16), y0, palColor, weighting);
1009 PUTTRANSDOT (x0 + (errorAcc >> 16) + xDir, y0,
1010 palColor, WEIGHTMASK - weighting);
1011 }
1012 }
1013 else
1014 {
1015 while (--deltaY)
1016 {
1017 errorAcc += errorAdj;
1018 y0++;
1019 int weighting = ((errorAcc * WeightingScale) >> (WEIGHTSHIFT+8)) & WEIGHTMASK;
1020 PUTTRANSDOT (x0 + (errorAcc >> 16), y0, palColor, weighting);
1021 PUTTRANSDOT (x0 + (errorAcc >> 16) + xDir, y0,
1022 palColor, WEIGHTMASK - weighting);
1023 }
1024 }
1025 }
1026 }
1027 else
1028 { // x-major line
1029 fixed_t errorAdj = (((DWORD) deltaY << 16) / (DWORD) deltaX) & 0xffff;
1030
1031 if (WeightingScale == 0)
1032 {
1033 while (--deltaX)
1034 {
1035 errorAcc += errorAdj;
1036 x0 += xDir;
1037 int weighting = (errorAcc >> WEIGHTSHIFT) & WEIGHTMASK;
1038 PUTTRANSDOT (x0, y0 + (errorAcc >> 16), palColor, weighting);
1039 PUTTRANSDOT (x0, y0 + (errorAcc >> 16) + 1,
1040 palColor, WEIGHTMASK - weighting);
1041 }
1042 }
1043 else
1044 {
1045 while (--deltaX)
1046 {
1047 errorAcc += errorAdj;
1048 x0 += xDir;
1049 int weighting = ((errorAcc * WeightingScale) >> (WEIGHTSHIFT+8)) & WEIGHTMASK;
1050 PUTTRANSDOT (x0, y0 + (errorAcc >> 16), palColor, weighting);
1051 PUTTRANSDOT (x0, y0 + (errorAcc >> 16) + 1,
1052 palColor, WEIGHTMASK - weighting);
1053 }
1054 }
1055 }
1056 PUTTRANSDOT (x1, y1, palColor, 0);
1057 }
1058 Unlock();
1059 }
1060
DrawPixel(int x,int y,int palColor,uint32 realcolor)1061 void DCanvas::DrawPixel(int x, int y, int palColor, uint32 realcolor)
1062 {
1063 if (palColor < 0)
1064 {
1065 palColor = PalFromRGB(realcolor);
1066 }
1067
1068 Buffer[Pitch * y + x] = (BYTE)palColor;
1069 }
1070
1071 //==========================================================================
1072 //
1073 // DCanvas :: Clear
1074 //
1075 // Set an area to a specified color.
1076 //
1077 //==========================================================================
1078
Clear(int left,int top,int right,int bottom,int palcolor,uint32 color)1079 void DCanvas::Clear (int left, int top, int right, int bottom, int palcolor, uint32 color)
1080 {
1081 int x, y;
1082 BYTE *dest;
1083
1084 if (left == right || top == bottom)
1085 {
1086 return;
1087 }
1088
1089 assert(left < right);
1090 assert(top < bottom);
1091
1092 if (left >= Width || right <= 0 || top >= Height || bottom <= 0)
1093 {
1094 return;
1095 }
1096 left = MAX(0,left);
1097 right = MIN(Width,right);
1098 top = MAX(0,top);
1099 bottom = MIN(Height,bottom);
1100
1101 if (palcolor < 0)
1102 {
1103 if (APART(color) != 255)
1104 {
1105 Dim(color, APART(color)/255.f, left, top, right - left, bottom - top);
1106 return;
1107 }
1108
1109 palcolor = PalFromRGB(color);
1110 }
1111
1112 dest = Buffer + top * Pitch + left;
1113 x = right - left;
1114 for (y = top; y < bottom; y++)
1115 {
1116 memset(dest, palcolor, x);
1117 dest += Pitch;
1118 }
1119 }
1120
1121 //==========================================================================
1122 //
1123 // DCanvas :: FillSimplePoly
1124 //
1125 // Fills a simple polygon with a texture. Here, "simple" means that a
1126 // horizontal scanline at any vertical position within the polygon will
1127 // not cross it more than twice.
1128 //
1129 // The originx, originy, scale, and rotation parameters specify
1130 // transformation of the filling texture, not of the points.
1131 //
1132 // The points must be specified in clockwise order.
1133 //
1134 //==========================================================================
1135
FillSimplePoly(FTexture * tex,FVector2 * points,int npoints,double originx,double originy,double scalex,double scaley,angle_t rotation,FDynamicColormap * colormap,int lightlevel)1136 void DCanvas::FillSimplePoly(FTexture *tex, FVector2 *points, int npoints,
1137 double originx, double originy, double scalex, double scaley, angle_t rotation,
1138 FDynamicColormap *colormap, int lightlevel)
1139 {
1140 #ifndef NO_SWRENDER
1141 // Use an equation similar to player sprites to determine shade
1142 fixed_t shade = LIGHT2SHADE(lightlevel) - 12*FRACUNIT;
1143 float topy, boty, leftx, rightx;
1144 int toppt, botpt, pt1, pt2;
1145 int i;
1146 int y1, y2, y;
1147 fixed_t x;
1148 double rot = rotation * M_PI / double(1u << 31);
1149 bool dorotate = rot != 0;
1150 double cosrot, sinrot;
1151
1152 if (--npoints < 2 || Buffer == NULL)
1153 { // not a polygon or we're not locked
1154 return;
1155 }
1156
1157 // Find the extents of the polygon, in particular the highest and lowest points.
1158 for (botpt = toppt = 0, boty = topy = points[0].Y, leftx = rightx = points[0].X, i = 1; i <= npoints; ++i)
1159 {
1160 if (points[i].Y < topy)
1161 {
1162 topy = points[i].Y;
1163 toppt = i;
1164 }
1165 if (points[i].Y > boty)
1166 {
1167 boty = points[i].Y;
1168 botpt = i;
1169 }
1170 if (points[i].X < leftx)
1171 {
1172 leftx = points[i].X;
1173 }
1174 if (points[i].X > rightx)
1175 {
1176 rightx = points[i].X;
1177 }
1178 }
1179 if (topy >= Height || // off the bottom of the screen
1180 boty <= 0 || // off the top of the screen
1181 leftx >= Width || // off the right of the screen
1182 rightx <= 0) // off the left of the screen
1183 {
1184 return;
1185 }
1186
1187 scalex /= FIXED2FLOAT(tex->xScale);
1188 scaley /= FIXED2FLOAT(tex->yScale);
1189
1190 cosrot = cos(rot);
1191 sinrot = sin(rot);
1192
1193 // Setup constant texture mapping parameters.
1194 R_SetupSpanBits(tex);
1195 R_SetSpanColormap(colormap != NULL ? &colormap->Maps[clamp(shade >> FRACBITS, 0, NUMCOLORMAPS-1) * 256] : identitymap);
1196 R_SetSpanSource(tex->GetPixels());
1197 scalex = double(1u << (32 - ds_xbits)) / scalex;
1198 scaley = double(1u << (32 - ds_ybits)) / scaley;
1199 ds_xstep = xs_RoundToInt(cosrot * scalex);
1200 ds_ystep = xs_RoundToInt(sinrot * scaley);
1201
1202 // Travel down the right edge and create an outline of that edge.
1203 pt1 = toppt;
1204 pt2 = toppt + 1; if (pt2 > npoints) pt2 = 0;
1205 y1 = xs_RoundToInt(points[pt1].Y + 0.5f);
1206 do
1207 {
1208 x = FLOAT2FIXED(points[pt1].X + 0.5f);
1209 y2 = xs_RoundToInt(points[pt2].Y + 0.5f);
1210 if (y1 >= y2 || (y1 < 0 && y2 < 0) || (y1 >= Height && y2 >= Height))
1211 {
1212 }
1213 else
1214 {
1215 fixed_t xinc = FLOAT2FIXED((points[pt2].X - points[pt1].X) / (points[pt2].Y - points[pt1].Y));
1216 int y3 = MIN(y2, Height);
1217 if (y1 < 0)
1218 {
1219 x += xinc * -y1;
1220 y1 = 0;
1221 }
1222 for (y = y1; y < y3; ++y)
1223 {
1224 spanend[y] = clamp<short>(x >> FRACBITS, -1, Width);
1225 x += xinc;
1226 }
1227 }
1228 y1 = y2;
1229 pt1 = pt2;
1230 pt2++; if (pt2 > npoints) pt2 = 0;
1231 } while (pt1 != botpt);
1232
1233 // Travel down the left edge and fill it in.
1234 pt1 = toppt;
1235 pt2 = toppt - 1; if (pt2 < 0) pt2 = npoints;
1236 y1 = xs_RoundToInt(points[pt1].Y + 0.5f);
1237 do
1238 {
1239 x = FLOAT2FIXED(points[pt1].X + 0.5f);
1240 y2 = xs_RoundToInt(points[pt2].Y + 0.5f);
1241 if (y1 >= y2 || (y1 < 0 && y2 < 0) || (y1 >= Height && y2 >= Height))
1242 {
1243 }
1244 else
1245 {
1246 fixed_t xinc = FLOAT2FIXED((points[pt2].X - points[pt1].X) / (points[pt2].Y - points[pt1].Y));
1247 int y3 = MIN(y2, Height);
1248 if (y1 < 0)
1249 {
1250 x += xinc * -y1;
1251 y1 = 0;
1252 }
1253 for (y = y1; y < y3; ++y)
1254 {
1255 int x1 = x >> FRACBITS;
1256 int x2 = spanend[y];
1257 if (x2 > x1 && x2 > 0 && x1 < Width)
1258 {
1259 x1 = MAX(x1, 0);
1260 x2 = MIN(x2, Width);
1261 #if 0
1262 memset(this->Buffer + y * this->Pitch + x1, (int)tex, x2 - x1);
1263 #else
1264 ds_y = y;
1265 ds_x1 = x1;
1266 ds_x2 = x2 - 1;
1267
1268 TVector2<double> tex(x1 - originx, y - originy);
1269 if (dorotate)
1270 {
1271 double t = tex.X;
1272 tex.X = t * cosrot - tex.Y * sinrot;
1273 tex.Y = tex.Y * cosrot + t * sinrot;
1274 }
1275 ds_xfrac = xs_RoundToInt(tex.X * scalex);
1276 ds_yfrac = xs_RoundToInt(tex.Y * scaley);
1277
1278 R_DrawSpan();
1279 #endif
1280 }
1281 x += xinc;
1282 }
1283 }
1284 y1 = y2;
1285 pt1 = pt2;
1286 pt2--; if (pt2 < 0) pt2 = npoints;
1287 } while (pt1 != botpt);
1288 #endif
1289 }
1290
1291
1292 /********************************/
1293 /* */
1294 /* Other miscellaneous routines */
1295 /* */
1296 /********************************/
1297
1298
1299 //
1300 // V_DrawBlock
1301 // Draw a linear block of pixels into the view buffer.
1302 //
DrawBlock(int x,int y,int _width,int _height,const BYTE * src) const1303 void DCanvas::DrawBlock (int x, int y, int _width, int _height, const BYTE *src) const
1304 {
1305 int srcpitch = _width;
1306 int destpitch;
1307 BYTE *dest;
1308
1309 if (ClipBox (x, y, _width, _height, src, srcpitch))
1310 {
1311 return; // Nothing to draw
1312 }
1313
1314 destpitch = Pitch;
1315 dest = Buffer + y*Pitch + x;
1316
1317 do
1318 {
1319 memcpy (dest, src, _width);
1320 src += srcpitch;
1321 dest += destpitch;
1322 } while (--_height);
1323 }
1324
1325 //
1326 // V_GetBlock
1327 // Gets a linear block of pixels from the view buffer.
1328 //
GetBlock(int x,int y,int _width,int _height,BYTE * dest) const1329 void DCanvas::GetBlock (int x, int y, int _width, int _height, BYTE *dest) const
1330 {
1331 const BYTE *src;
1332
1333 #ifdef RANGECHECK
1334 if (x<0
1335 ||x+_width > Width
1336 || y<0
1337 || y+_height>Height)
1338 {
1339 I_Error ("Bad V_GetBlock");
1340 }
1341 #endif
1342
1343 src = Buffer + y*Pitch + x;
1344
1345 while (_height--)
1346 {
1347 memcpy (dest, src, _width);
1348 src += Pitch;
1349 dest += _width;
1350 }
1351 }
1352
1353 // Returns true if the box was completely clipped. False otherwise.
ClipBox(int & x,int & y,int & w,int & h,const BYTE * & src,const int srcpitch) const1354 bool DCanvas::ClipBox (int &x, int &y, int &w, int &h, const BYTE *&src, const int srcpitch) const
1355 {
1356 if (x >= Width || y >= Height || x+w <= 0 || y+h <= 0)
1357 { // Completely clipped off screen
1358 return true;
1359 }
1360 if (x < 0) // clip left edge
1361 {
1362 src -= x;
1363 w += x;
1364 x = 0;
1365 }
1366 if (x+w > Width) // clip right edge
1367 {
1368 w = Width - x;
1369 }
1370 if (y < 0) // clip top edge
1371 {
1372 src -= y*srcpitch;
1373 h += y;
1374 y = 0;
1375 }
1376 if (y+h > Height) // clip bottom edge
1377 {
1378 h = Height - y;
1379 }
1380 return false;
1381 }
1382
1383 //==========================================================================
1384 //
1385 // V_SetBorderNeedRefresh
1386 //
1387 // Flag the border as in need of updating. (Probably because something that
1388 // was on top of it has changed.
1389 //
1390 //==========================================================================
1391
V_SetBorderNeedRefresh()1392 void V_SetBorderNeedRefresh()
1393 {
1394 if (screen != NULL)
1395 {
1396 BorderNeedRefresh = screen->GetPageCount();
1397 }
1398 }
1399
1400 //==========================================================================
1401 //
1402 // V_DrawFrame
1403 //
1404 // Draw a frame around the specified area using the view border
1405 // frame graphics. The border is drawn outside the area, not in it.
1406 //
1407 //==========================================================================
1408
V_DrawFrame(int left,int top,int width,int height)1409 void V_DrawFrame (int left, int top, int width, int height)
1410 {
1411 FTexture *p;
1412 const gameborder_t *border = &gameinfo.Border;
1413 // Sanity check for incomplete gameinfo
1414 if (border == NULL)
1415 return;
1416 int offset = border->offset;
1417 int right = left + width;
1418 int bottom = top + height;
1419
1420 // Draw top and bottom sides.
1421 p = TexMan[border->t];
1422 screen->FlatFill(left, top - p->GetHeight(), right, top, p, true);
1423 p = TexMan[border->b];
1424 screen->FlatFill(left, bottom, right, bottom + p->GetHeight(), p, true);
1425
1426 // Draw left and right sides.
1427 p = TexMan[border->l];
1428 screen->FlatFill(left - p->GetWidth(), top, left, bottom, p, true);
1429 p = TexMan[border->r];
1430 screen->FlatFill(right, top, right + p->GetWidth(), bottom, p, true);
1431
1432 // Draw beveled corners.
1433 screen->DrawTexture (TexMan[border->tl], left-offset, top-offset, TAG_DONE);
1434 screen->DrawTexture (TexMan[border->tr], left+width, top-offset, TAG_DONE);
1435 screen->DrawTexture (TexMan[border->bl], left-offset, top+height, TAG_DONE);
1436 screen->DrawTexture (TexMan[border->br], left+width, top+height, TAG_DONE);
1437 }
1438
1439 //==========================================================================
1440 //
1441 // V_DrawBorder
1442 //
1443 //==========================================================================
1444
V_DrawBorder(int x1,int y1,int x2,int y2)1445 void V_DrawBorder (int x1, int y1, int x2, int y2)
1446 {
1447 FTextureID picnum;
1448
1449 if (level.info != NULL && level.info->BorderTexture.Len() != 0)
1450 {
1451 picnum = TexMan.CheckForTexture (level.info->BorderTexture, FTexture::TEX_Flat);
1452 }
1453 else
1454 {
1455 picnum = TexMan.CheckForTexture (gameinfo.BorderFlat, FTexture::TEX_Flat);
1456 }
1457
1458 if (picnum.isValid())
1459 {
1460 screen->FlatFill (x1, y1, x2, y2, TexMan(picnum));
1461 }
1462 else
1463 {
1464 screen->Clear (x1, y1, x2, y2, 0, 0);
1465 }
1466 }
1467
1468 //==========================================================================
1469 //
1470 // R_DrawViewBorder
1471 //
1472 // Draws the border around the view for different size windows
1473 //
1474 //==========================================================================
1475
1476 int BorderNeedRefresh;
1477
1478
V_DrawViewBorder(void)1479 static void V_DrawViewBorder (void)
1480 {
1481 // [RH] Redraw the status bar if SCREENWIDTH > status bar width.
1482 // Will draw borders around itself, too.
1483 if (SCREENWIDTH > 320)
1484 {
1485 ST_SetNeedRefresh();
1486 }
1487
1488 if (viewwidth == SCREENWIDTH)
1489 {
1490 return;
1491 }
1492
1493 V_DrawBorder (0, 0, SCREENWIDTH, viewwindowy);
1494 V_DrawBorder (0, viewwindowy, viewwindowx, viewheight + viewwindowy);
1495 V_DrawBorder (viewwindowx + viewwidth, viewwindowy, SCREENWIDTH, viewheight + viewwindowy);
1496 V_DrawBorder (0, viewwindowy + viewheight, SCREENWIDTH, ST_Y);
1497
1498 V_DrawFrame (viewwindowx, viewwindowy, viewwidth, viewheight);
1499 V_MarkRect (0, 0, SCREENWIDTH, ST_Y);
1500 }
1501
1502 //==========================================================================
1503 //
1504 // R_DrawTopBorder
1505 //
1506 // Draws the top border around the view for different size windows
1507 //
1508 //==========================================================================
1509
V_DrawTopBorder()1510 static void V_DrawTopBorder ()
1511 {
1512 FTexture *p;
1513 int offset;
1514
1515 if (viewwidth == SCREENWIDTH)
1516 return;
1517
1518 offset = gameinfo.Border.offset;
1519
1520 if (viewwindowy < 34)
1521 {
1522 V_DrawBorder (0, 0, viewwindowx, 34);
1523 V_DrawBorder (viewwindowx, 0, viewwindowx + viewwidth, viewwindowy);
1524 V_DrawBorder (viewwindowx + viewwidth, 0, SCREENWIDTH, 34);
1525 p = TexMan(gameinfo.Border.t);
1526 screen->FlatFill(viewwindowx, viewwindowy - p->GetHeight(),
1527 viewwindowx + viewwidth, viewwindowy, p, true);
1528
1529 p = TexMan(gameinfo.Border.l);
1530 screen->FlatFill(viewwindowx - p->GetWidth(), viewwindowy,
1531 viewwindowx, 35, p, true);
1532 p = TexMan(gameinfo.Border.r);
1533 screen->FlatFill(viewwindowx + viewwidth, viewwindowy,
1534 viewwindowx + viewwidth + p->GetWidth(), 35, p, true);
1535
1536 p = TexMan(gameinfo.Border.tl);
1537 screen->DrawTexture (p, viewwindowx - offset, viewwindowy - offset, TAG_DONE);
1538
1539 p = TexMan(gameinfo.Border.tr);
1540 screen->DrawTexture (p, viewwindowx + viewwidth, viewwindowy - offset, TAG_DONE);
1541 }
1542 else
1543 {
1544 V_DrawBorder (0, 0, SCREENWIDTH, 34);
1545 }
1546 }
1547
1548 //==========================================================================
1549 //
1550 // R_RefreshViewBorder
1551 //
1552 // Draws the border around the player view, if needed.
1553 //
1554 //==========================================================================
1555
V_RefreshViewBorder()1556 void V_RefreshViewBorder ()
1557 {
1558 if (setblocks < 10)
1559 {
1560 if (BorderNeedRefresh)
1561 {
1562 BorderNeedRefresh--;
1563 if (BorderTopRefresh)
1564 {
1565 BorderTopRefresh--;
1566 }
1567 V_DrawViewBorder();
1568 }
1569 else if (BorderTopRefresh)
1570 {
1571 BorderTopRefresh--;
1572 V_DrawTopBorder();
1573 }
1574 }
1575 }
1576
1577