1 // SONIC ROBO BLAST 2
2 //-----------------------------------------------------------------------------
3 // Copyright (C) 1998-2000 by DooM Legacy Team.
4 // Copyright (C) 1999-2020 by Sonic Team Junior.
5 //
6 // This program is free software distributed under the
7 // terms of the GNU General Public License, version 2.
8 // See the 'LICENSE' file for more details.
9 //-----------------------------------------------------------------------------
10 /// \file hw_draw.c
11 /// \brief miscellaneous drawing (mainly 2d)
12
13 #ifdef __GNUC__
14 #include <unistd.h>
15 #endif
16
17 #include "../doomdef.h"
18
19 #ifdef HWRENDER
20 #include "hw_main.h"
21 #include "hw_glob.h"
22 #include "hw_drv.h"
23
24 #include "../m_misc.h" //FIL_WriteFile()
25 #include "../r_draw.h" //viewborderlump
26 #include "../r_main.h"
27 #include "../w_wad.h"
28 #include "../z_zone.h"
29 #include "../v_video.h"
30 #include "../st_stuff.h"
31 #include "../p_local.h" // stplyr
32 #include "../g_game.h" // players
33
34 #include <fcntl.h>
35 #include "../i_video.h" // for rendermode != render_glide
36
37 #ifndef O_BINARY
38 #define O_BINARY 0
39 #endif
40
41 #if defined(_MSC_VER)
42 #pragma pack(1)
43 #endif
44 typedef struct
45 {
46 UINT8 id_field_length ; // 1
47 UINT8 color_map_type ; // 2
48 UINT8 image_type ; // 3
49 UINT8 dummy[5] ; // 4, 8
50 INT16 x_origin ; // 9, 10
51 INT16 y_origin ; //11, 12
52 INT16 width ; //13, 14
53 INT16 height ; //15, 16
54 UINT8 image_pix_size ; //17
55 UINT8 image_descriptor; //18
56 } ATTRPACK TGAHeader; // sizeof is 18
57 #if defined(_MSC_VER)
58 #pragma pack()
59 #endif
60
61 static UINT8 softwaretranstogl[11] = { 0, 25, 51, 76,102,127,153,178,204,229,255};
62 static UINT8 softwaretranstogl_hi[11] = { 0, 51,102,153,204,255,255,255,255,255,255};
63 static UINT8 softwaretranstogl_lo[11] = { 0, 12, 24, 36, 48, 60, 71, 83, 95,111,127};
64
65 //
66 // -----------------+
67 // HWR_DrawPatch : Draw a 'tile' graphic
68 // Notes : x,y : positions relative to the original Doom resolution
69 // : textes(console+score) + menus + status bar
70 // -----------------+
HWR_DrawPatch(patch_t * gpatch,INT32 x,INT32 y,INT32 option)71 void HWR_DrawPatch(patch_t *gpatch, INT32 x, INT32 y, INT32 option)
72 {
73 FOutVector v[4];
74 FBITFIELD flags;
75 GLPatch_t *hwrPatch;
76
77 // 3--2
78 // | /|
79 // |/ |
80 // 0--1
81 float sdupx = FIXED_TO_FLOAT(vid.fdupx)*2.0f;
82 float sdupy = FIXED_TO_FLOAT(vid.fdupy)*2.0f;
83 float pdupx = FIXED_TO_FLOAT(vid.fdupx)*2.0f;
84 float pdupy = FIXED_TO_FLOAT(vid.fdupy)*2.0f;
85
86 // make patch ready in hardware cache
87 HWR_GetPatch(gpatch);
88 hwrPatch = ((GLPatch_t *)gpatch->hardware);
89
90 switch (option & V_SCALEPATCHMASK)
91 {
92 case V_NOSCALEPATCH:
93 pdupx = pdupy = 2.0f;
94 break;
95 case V_SMALLSCALEPATCH:
96 pdupx = 2.0f * FIXED_TO_FLOAT(vid.fsmalldupx);
97 pdupy = 2.0f * FIXED_TO_FLOAT(vid.fsmalldupy);
98 break;
99 case V_MEDSCALEPATCH:
100 pdupx = 2.0f * FIXED_TO_FLOAT(vid.fmeddupx);
101 pdupy = 2.0f * FIXED_TO_FLOAT(vid.fmeddupy);
102 break;
103 }
104
105 if (option & V_NOSCALESTART)
106 sdupx = sdupy = 2.0f;
107
108 v[0].x = v[3].x = (x*sdupx-(gpatch->leftoffset)*pdupx)/vid.width - 1;
109 v[2].x = v[1].x = (x*sdupx+(gpatch->width-gpatch->leftoffset)*pdupx)/vid.width - 1;
110 v[0].y = v[1].y = 1-(y*sdupy-(gpatch->topoffset)*pdupy)/vid.height;
111 v[2].y = v[3].y = 1-(y*sdupy+(gpatch->height-gpatch->topoffset)*pdupy)/vid.height;
112
113 v[0].z = v[1].z = v[2].z = v[3].z = 1.0f;
114
115 v[0].s = v[3].s = 0.0f;
116 v[2].s = v[1].s = hwrPatch->max_s;
117 v[0].t = v[1].t = 0.0f;
118 v[2].t = v[3].t = hwrPatch->max_t;
119
120 flags = PF_Translucent|PF_NoDepthTest;
121
122 if (option & V_WRAPX)
123 flags |= PF_ForceWrapX;
124 if (option & V_WRAPY)
125 flags |= PF_ForceWrapY;
126
127 // clip it since it is used for bunny scroll in doom I
128 HWD.pfnDrawPolygon(NULL, v, 4, flags);
129 }
130
HWR_DrawStretchyFixedPatch(patch_t * gpatch,fixed_t x,fixed_t y,fixed_t pscale,fixed_t vscale,INT32 option,const UINT8 * colormap)131 void HWR_DrawStretchyFixedPatch(patch_t *gpatch, fixed_t x, fixed_t y, fixed_t pscale, fixed_t vscale, INT32 option, const UINT8 *colormap)
132 {
133 FOutVector v[4];
134 FBITFIELD flags;
135 float cx = FIXED_TO_FLOAT(x);
136 float cy = FIXED_TO_FLOAT(y);
137 UINT8 alphalevel = ((option & V_ALPHAMASK) >> V_ALPHASHIFT);
138 GLPatch_t *hwrPatch;
139
140 // 3--2
141 // | /|
142 // |/ |
143 // 0--1
144 float dupx, dupy, fscalew, fscaleh, fwidth, fheight;
145
146 UINT8 perplayershuffle = 0;
147
148 if (alphalevel >= 10 && alphalevel < 13)
149 return;
150
151 // make patch ready in hardware cache
152 if (!colormap)
153 HWR_GetPatch(gpatch);
154 else
155 HWR_GetMappedPatch(gpatch, colormap);
156
157 hwrPatch = ((GLPatch_t *)gpatch->hardware);
158
159 dupx = (float)vid.dupx;
160 dupy = (float)vid.dupy;
161
162 switch (option & V_SCALEPATCHMASK)
163 {
164 case V_NOSCALEPATCH:
165 dupx = dupy = 1.0f;
166 break;
167 case V_SMALLSCALEPATCH:
168 dupx = (float)vid.smalldupx;
169 dupy = (float)vid.smalldupy;
170 break;
171 case V_MEDSCALEPATCH:
172 dupx = (float)vid.meddupx;
173 dupy = (float)vid.meddupy;
174 break;
175 }
176
177 dupx = dupy = (dupx < dupy ? dupx : dupy);
178 fscalew = fscaleh = FIXED_TO_FLOAT(pscale);
179 if (vscale != pscale)
180 fscaleh = FIXED_TO_FLOAT(vscale);
181
182 // See my comments in v_video.c's V_DrawFixedPatch
183 // -- Monster Iestyn 29/10/18
184 {
185 float offsetx = 0.0f, offsety = 0.0f;
186
187 // left offset
188 if (option & V_FLIP)
189 offsetx = (float)(gpatch->width - gpatch->leftoffset) * fscalew;
190 else
191 offsetx = (float)(gpatch->leftoffset) * fscalew;
192
193 // top offset
194 // TODO: make some kind of vertical version of V_FLIP, maybe by deprecating V_OFFSET in future?!?
195 offsety = (float)(gpatch->topoffset) * fscaleh;
196
197 if ((option & (V_NOSCALESTART|V_OFFSET)) == (V_NOSCALESTART|V_OFFSET)) // Multiply by dupx/dupy for crosshairs
198 {
199 offsetx *= dupx;
200 offsety *= dupy;
201 }
202
203 cx -= offsetx;
204 cy -= offsety;
205 }
206
207 if (splitscreen && (option & V_PERPLAYER))
208 {
209 float adjusty = ((option & V_NOSCALESTART) ? vid.height : BASEVIDHEIGHT)/2.0f;
210 fscaleh /= 2;
211 cy /= 2;
212 #ifdef QUADS
213 if (splitscreen > 1) // 3 or 4 players
214 {
215 float adjustx = ((option & V_NOSCALESTART) ? vid.width : BASEVIDWIDTH)/2.0f;
216 fscalew /= 2;
217 cx /= 2;
218 if (stplyr == &players[displayplayer])
219 {
220 if (!(option & (V_SNAPTOTOP|V_SNAPTOBOTTOM)))
221 perplayershuffle |= 1;
222 if (!(option & (V_SNAPTOLEFT|V_SNAPTORIGHT)))
223 perplayershuffle |= 4;
224 option &= ~V_SNAPTOBOTTOM|V_SNAPTORIGHT;
225 }
226 else if (stplyr == &players[secondarydisplayplayer])
227 {
228 if (!(option & (V_SNAPTOTOP|V_SNAPTOBOTTOM)))
229 perplayershuffle |= 1;
230 if (!(option & (V_SNAPTOLEFT|V_SNAPTORIGHT)))
231 perplayershuffle |= 8;
232 cx += adjustx;
233 option &= ~V_SNAPTOBOTTOM|V_SNAPTOLEFT;
234 }
235 else if (stplyr == &players[thirddisplayplayer])
236 {
237 if (!(option & (V_SNAPTOTOP|V_SNAPTOBOTTOM)))
238 perplayershuffle |= 2;
239 if (!(option & (V_SNAPTOLEFT|V_SNAPTORIGHT)))
240 perplayershuffle |= 4;
241 cy += adjusty;
242 option &= ~V_SNAPTOTOP|V_SNAPTORIGHT;
243 }
244 else if (stplyr == &players[fourthdisplayplayer])
245 {
246 if (!(option & (V_SNAPTOTOP|V_SNAPTOBOTTOM)))
247 perplayershuffle |= 2;
248 if (!(option & (V_SNAPTOLEFT|V_SNAPTORIGHT)))
249 perplayershuffle |= 8;
250 cx += adjustx;
251 cy += adjusty;
252 option &= ~V_SNAPTOTOP|V_SNAPTOLEFT;
253 }
254 }
255 else
256 #endif
257 // 2 players
258 {
259 if (stplyr == &players[displayplayer])
260 {
261 if (!(option & (V_SNAPTOTOP|V_SNAPTOBOTTOM)))
262 perplayershuffle = 1;
263 option &= ~V_SNAPTOBOTTOM;
264 }
265 else //if (stplyr == &players[secondarydisplayplayer])
266 {
267 if (!(option & (V_SNAPTOTOP|V_SNAPTOBOTTOM)))
268 perplayershuffle = 2;
269 cy += adjusty;
270 option &= ~V_SNAPTOTOP;
271 }
272 }
273 }
274
275 if (!(option & V_NOSCALESTART))
276 {
277 cx = cx * dupx;
278 cy = cy * dupy;
279
280 if (!(option & V_SCALEPATCHMASK))
281 {
282 // if it's meant to cover the whole screen, black out the rest (ONLY IF TOP LEFT ISN'T TRANSPARENT)
283 // cx and cy are possibly *slightly* off from float maths
284 // This is done before here compared to software because we directly alter cx and cy to centre
285 if (cx >= -0.1f && cx <= 0.1f && gpatch->width == BASEVIDWIDTH && cy >= -0.1f && cy <= 0.1f && gpatch->height == BASEVIDHEIGHT)
286 {
287 const column_t *column = (const column_t *)((const UINT8 *)(gpatch->columns) + (gpatch->columnofs[0]));
288 if (!column->topdelta)
289 {
290 const UINT8 *source = (const UINT8 *)(column) + 3;
291 HWR_DrawFill(0, 0, BASEVIDWIDTH, BASEVIDHEIGHT, (column->topdelta == 0xff ? 31 : source[0]));
292 }
293 }
294 // centre screen
295 if (fabsf((float)vid.width - (float)BASEVIDWIDTH * dupx) > 1.0E-36f)
296 {
297 if (option & V_SNAPTORIGHT)
298 cx += ((float)vid.width - ((float)BASEVIDWIDTH * dupx));
299 else if (!(option & V_SNAPTOLEFT))
300 cx += ((float)vid.width - ((float)BASEVIDWIDTH * dupx))/2;
301 if (perplayershuffle & 4)
302 cx -= ((float)vid.width - ((float)BASEVIDWIDTH * dupx))/4;
303 else if (perplayershuffle & 8)
304 cx += ((float)vid.width - ((float)BASEVIDWIDTH * dupx))/4;
305 }
306 if (fabsf((float)vid.height - (float)BASEVIDHEIGHT * dupy) > 1.0E-36f)
307 {
308 if (option & V_SNAPTOBOTTOM)
309 cy += ((float)vid.height - ((float)BASEVIDHEIGHT * dupy));
310 else if (!(option & V_SNAPTOTOP))
311 cy += ((float)vid.height - ((float)BASEVIDHEIGHT * dupy))/2;
312 if (perplayershuffle & 1)
313 cy -= ((float)vid.height - ((float)BASEVIDHEIGHT * dupy))/4;
314 else if (perplayershuffle & 2)
315 cy += ((float)vid.height - ((float)BASEVIDHEIGHT * dupy))/4;
316 }
317 }
318 }
319
320 if (pscale != FRACUNIT || (splitscreen && option & V_PERPLAYER))
321 {
322 fwidth = (float)(gpatch->width) * fscalew * dupx;
323 fheight = (float)(gpatch->height) * fscaleh * dupy;
324 }
325 else
326 {
327 fwidth = (float)(gpatch->width) * dupx;
328 fheight = (float)(gpatch->height) * dupy;
329 }
330
331 // positions of the cx, cy, are between 0 and vid.width/vid.height now, we need them to be between -1 and 1
332 cx = -1 + (cx / (vid.width/2));
333 cy = 1 - (cy / (vid.height/2));
334
335 // fwidth and fheight are similar
336 fwidth /= vid.width / 2;
337 fheight /= vid.height / 2;
338
339 // set the polygon vertices to the right positions
340 v[0].x = v[3].x = cx;
341 v[2].x = v[1].x = cx + fwidth;
342
343 v[0].y = v[1].y = cy;
344 v[2].y = v[3].y = cy - fheight;
345
346 v[0].z = v[1].z = v[2].z = v[3].z = 1.0f;
347
348 if (option & V_FLIP)
349 {
350 v[0].s = v[3].s = hwrPatch->max_s;
351 v[2].s = v[1].s = 0.0f;
352 }
353 else
354 {
355 v[0].s = v[3].s = 0.0f;
356 v[2].s = v[1].s = hwrPatch->max_s;
357 }
358
359 v[0].t = v[1].t = 0.0f;
360 v[2].t = v[3].t = hwrPatch->max_t;
361
362 flags = PF_Translucent|PF_NoDepthTest;
363
364 if (option & V_WRAPX)
365 flags |= PF_ForceWrapX;
366 if (option & V_WRAPY)
367 flags |= PF_ForceWrapY;
368
369 // clip it since it is used for bunny scroll in doom I
370 if (alphalevel)
371 {
372 FSurfaceInfo Surf;
373 Surf.PolyColor.s.red = Surf.PolyColor.s.green = Surf.PolyColor.s.blue = 0xff;
374 if (alphalevel == 13) Surf.PolyColor.s.alpha = softwaretranstogl_lo[st_translucency];
375 else if (alphalevel == 14) Surf.PolyColor.s.alpha = softwaretranstogl[st_translucency];
376 else if (alphalevel == 15) Surf.PolyColor.s.alpha = softwaretranstogl_hi[st_translucency];
377 else Surf.PolyColor.s.alpha = softwaretranstogl[10-alphalevel];
378 flags |= PF_Modulated;
379 HWD.pfnDrawPolygon(&Surf, v, 4, flags);
380 }
381 else
382 HWD.pfnDrawPolygon(NULL, v, 4, flags);
383 }
384
HWR_DrawCroppedPatch(patch_t * gpatch,fixed_t x,fixed_t y,fixed_t pscale,INT32 option,fixed_t sx,fixed_t sy,fixed_t w,fixed_t h)385 void HWR_DrawCroppedPatch(patch_t *gpatch, fixed_t x, fixed_t y, fixed_t pscale, INT32 option, fixed_t sx, fixed_t sy, fixed_t w, fixed_t h)
386 {
387 FOutVector v[4];
388 FBITFIELD flags;
389 float cx = FIXED_TO_FLOAT(x);
390 float cy = FIXED_TO_FLOAT(y);
391 UINT8 alphalevel = ((option & V_ALPHAMASK) >> V_ALPHASHIFT);
392 GLPatch_t *hwrPatch;
393
394 // 3--2
395 // | /|
396 // |/ |
397 // 0--1
398 float dupx, dupy, fscale, fwidth, fheight;
399
400 if (alphalevel >= 10 && alphalevel < 13)
401 return;
402
403 // make patch ready in hardware cache
404 HWR_GetPatch(gpatch);
405 hwrPatch = ((GLPatch_t *)gpatch->hardware);
406
407 dupx = (float)vid.dupx;
408 dupy = (float)vid.dupy;
409
410 switch (option & V_SCALEPATCHMASK)
411 {
412 case V_NOSCALEPATCH:
413 dupx = dupy = 1.0f;
414 break;
415 case V_SMALLSCALEPATCH:
416 dupx = (float)vid.smalldupx;
417 dupy = (float)vid.smalldupy;
418 break;
419 case V_MEDSCALEPATCH:
420 dupx = (float)vid.meddupx;
421 dupy = (float)vid.meddupy;
422 break;
423 }
424
425 dupx = dupy = (dupx < dupy ? dupx : dupy);
426 fscale = FIXED_TO_FLOAT(pscale);
427
428 // fuck it, no GL support for croppedpatch v_perplayer right now. it's not like it's accessible to Lua or anything, and we only use it for menus...
429
430 cy -= (float)(gpatch->topoffset) * fscale;
431 cx -= (float)(gpatch->leftoffset) * fscale;
432
433 if (!(option & V_NOSCALESTART))
434 {
435 cx = cx * dupx;
436 cy = cy * dupy;
437
438 if (!(option & V_SCALEPATCHMASK))
439 {
440 // if it's meant to cover the whole screen, black out the rest
441 // no the patch is cropped do not do this ever
442
443 // centre screen
444 if (fabsf((float)vid.width - (float)BASEVIDWIDTH * dupx) > 1.0E-36f)
445 {
446 if (option & V_SNAPTORIGHT)
447 cx += ((float)vid.width - ((float)BASEVIDWIDTH * dupx));
448 else if (!(option & V_SNAPTOLEFT))
449 cx += ((float)vid.width - ((float)BASEVIDWIDTH * dupx))/2;
450 }
451 if (fabsf((float)vid.height - (float)BASEVIDHEIGHT * dupy) > 1.0E-36f)
452 {
453 if (option & V_SNAPTOBOTTOM)
454 cy += ((float)vid.height - ((float)BASEVIDHEIGHT * dupy));
455 else if (!(option & V_SNAPTOTOP))
456 cy += ((float)vid.height - ((float)BASEVIDHEIGHT * dupy))/2;
457 }
458 }
459 }
460
461 fwidth = w;
462 fheight = h;
463
464 if (sx + w > gpatch->width)
465 fwidth = gpatch->width - sx;
466
467 if (sy + h > gpatch->height)
468 fheight = gpatch->height - sy;
469
470 if (pscale != FRACUNIT)
471 {
472 fwidth *= fscale * dupx;
473 fheight *= fscale * dupy;
474 }
475 else
476 {
477 fwidth *= dupx;
478 fheight *= dupy;
479 }
480
481 // positions of the cx, cy, are between 0 and vid.width/vid.height now, we need them to be between -1 and 1
482 cx = -1 + (cx / (vid.width/2));
483 cy = 1 - (cy / (vid.height/2));
484
485 // fwidth and fheight are similar
486 fwidth /= vid.width / 2;
487 fheight /= vid.height / 2;
488
489 // set the polygon vertices to the right positions
490 v[0].x = v[3].x = cx;
491 v[2].x = v[1].x = cx + fwidth;
492
493 v[0].y = v[1].y = cy;
494 v[2].y = v[3].y = cy - fheight;
495
496 v[0].z = v[1].z = v[2].z = v[3].z = 1.0f;
497
498 v[0].s = v[3].s = ((sx)/(float)(gpatch->width))*hwrPatch->max_s;
499 if (sx + w > gpatch->width)
500 v[2].s = v[1].s = hwrPatch->max_s;
501 else
502 v[2].s = v[1].s = ((sx+w)/(float)(gpatch->width))*hwrPatch->max_s;
503
504 v[0].t = v[1].t = ((sy)/(float)(gpatch->height))*hwrPatch->max_t;
505 if (sy + h > gpatch->height)
506 v[2].t = v[3].t = hwrPatch->max_t;
507 else
508 v[2].t = v[3].t = ((sy+h)/(float)(gpatch->height))*hwrPatch->max_t;
509
510 flags = PF_Translucent|PF_NoDepthTest;
511
512 if (option & V_WRAPX)
513 flags |= PF_ForceWrapX;
514 if (option & V_WRAPY)
515 flags |= PF_ForceWrapY;
516
517 // clip it since it is used for bunny scroll in doom I
518 if (alphalevel)
519 {
520 FSurfaceInfo Surf;
521 Surf.PolyColor.s.red = Surf.PolyColor.s.green = Surf.PolyColor.s.blue = 0xff;
522 if (alphalevel == 13) Surf.PolyColor.s.alpha = softwaretranstogl_lo[st_translucency];
523 else if (alphalevel == 14) Surf.PolyColor.s.alpha = softwaretranstogl[st_translucency];
524 else if (alphalevel == 15) Surf.PolyColor.s.alpha = softwaretranstogl_hi[st_translucency];
525 else Surf.PolyColor.s.alpha = softwaretranstogl[10-alphalevel];
526 flags |= PF_Modulated;
527 HWD.pfnDrawPolygon(&Surf, v, 4, flags);
528 }
529 else
530 HWD.pfnDrawPolygon(NULL, v, 4, flags);
531 }
532
HWR_DrawPic(INT32 x,INT32 y,lumpnum_t lumpnum)533 void HWR_DrawPic(INT32 x, INT32 y, lumpnum_t lumpnum)
534 {
535 FOutVector v[4];
536 const patch_t *patch;
537
538 // make pic ready in hardware cache
539 patch = HWR_GetPic(lumpnum);
540
541 // 3--2
542 // | /|
543 // |/ |
544 // 0--1
545
546 v[0].x = v[3].x = 2.0f * (float)x/vid.width - 1;
547 v[2].x = v[1].x = 2.0f * (float)(x + patch->width*FIXED_TO_FLOAT(vid.fdupx))/vid.width - 1;
548 v[0].y = v[1].y = 1.0f - 2.0f * (float)y/vid.height;
549 v[2].y = v[3].y = 1.0f - 2.0f * (float)(y + patch->height*FIXED_TO_FLOAT(vid.fdupy))/vid.height;
550
551 v[0].z = v[1].z = v[2].z = v[3].z = 1.0f;
552
553 v[0].s = v[3].s = 0;
554 v[2].s = v[1].s = ((GLPatch_t *)patch->hardware)->max_s;
555 v[0].t = v[1].t = 0;
556 v[2].t = v[3].t = ((GLPatch_t *)patch->hardware)->max_t;
557
558
559 //Hurdler: Boris, the same comment as above... but maybe for pics
560 // it not a problem since they don't have any transparent pixel
561 // if I'm right !?
562 // But then, the question is: why not 0 instead of PF_Masked ?
563 // or maybe PF_Environment ??? (like what I said above)
564 // BP: PF_Environment don't change anything ! and 0 is undifined
565 HWD.pfnDrawPolygon(NULL, v, 4, PF_Translucent | PF_NoDepthTest);
566 }
567
568 // ==========================================================================
569 // V_VIDEO.C STUFF
570 // ==========================================================================
571
572
573 // --------------------------------------------------------------------------
574 // Fills a box of pixels using a flat texture as a pattern
575 // --------------------------------------------------------------------------
HWR_DrawFlatFill(INT32 x,INT32 y,INT32 w,INT32 h,lumpnum_t flatlumpnum)576 void HWR_DrawFlatFill (INT32 x, INT32 y, INT32 w, INT32 h, lumpnum_t flatlumpnum)
577 {
578 FOutVector v[4];
579 double dflatsize;
580 INT32 flatflag;
581 const size_t len = W_LumpLength(flatlumpnum);
582
583 switch (len)
584 {
585 case 4194304: // 2048x2048 lump
586 dflatsize = 2048.0f;
587 flatflag = 2047;
588 break;
589 case 1048576: // 1024x1024 lump
590 dflatsize = 1024.0f;
591 flatflag = 1023;
592 break;
593 case 262144:// 512x512 lump
594 dflatsize = 512.0f;
595 flatflag = 511;
596 break;
597 case 65536: // 256x256 lump
598 dflatsize = 256.0f;
599 flatflag = 255;
600 break;
601 case 16384: // 128x128 lump
602 dflatsize = 128.0f;
603 flatflag = 127;
604 break;
605 case 1024: // 32x32 lump
606 dflatsize = 32.0f;
607 flatflag = 31;
608 break;
609 default: // 64x64 lump
610 dflatsize = 64.0f;
611 flatflag = 63;
612 break;
613 }
614
615 // 3--2
616 // | /|
617 // |/ |
618 // 0--1
619
620 v[0].x = v[3].x = (x - 160.0f)/160.0f;
621 v[2].x = v[1].x = ((x+w) - 160.0f)/160.0f;
622 v[0].y = v[1].y = -(y - 100.0f)/100.0f;
623 v[2].y = v[3].y = -((y+h) - 100.0f)/100.0f;
624
625 v[0].z = v[1].z = v[2].z = v[3].z = 1.0f;
626
627 // flat is 64x64 lod and texture offsets are [0.0, 1.0]
628 v[0].s = v[3].s = (float)((x & flatflag)/dflatsize);
629 v[2].s = v[1].s = (float)(v[0].s + w/dflatsize);
630 v[0].t = v[1].t = (float)((y & flatflag)/dflatsize);
631 v[2].t = v[3].t = (float)(v[0].t + h/dflatsize);
632
633 HWR_GetRawFlat(flatlumpnum);
634
635 //Hurdler: Boris, the same comment as above... but maybe for pics
636 // it not a problem since they don't have any transparent pixel
637 // if I'm right !?
638 // BTW, I see we put 0 for PFs, and If I'm right, that
639 // means we take the previous PFs as default
640 // how can we be sure they are ok?
641 HWD.pfnDrawPolygon(NULL, v, 4, PF_NoDepthTest); //PF_Translucent);
642 }
643
644
645 // --------------------------------------------------------------------------
646 // Fade down the screen so that the menu drawn on top of it looks brighter
647 // --------------------------------------------------------------------------
648 // 3--2
649 // | /|
650 // |/ |
651 // 0--1
HWR_FadeScreenMenuBack(UINT16 color,UINT8 strength)652 void HWR_FadeScreenMenuBack(UINT16 color, UINT8 strength)
653 {
654 FOutVector v[4];
655 FSurfaceInfo Surf;
656
657 v[0].x = v[3].x = -1.0f;
658 v[2].x = v[1].x = 1.0f;
659 v[0].y = v[1].y = -1.0f;
660 v[2].y = v[3].y = 1.0f;
661 v[0].z = v[1].z = v[2].z = v[3].z = 1.0f;
662
663 v[0].s = v[3].s = 0.0f;
664 v[2].s = v[1].s = 1.0f;
665 v[0].t = v[1].t = 1.0f;
666 v[2].t = v[3].t = 0.0f;
667
668 if (color & 0xFF00) // Do COLORMAP fade.
669 {
670 Surf.PolyColor.rgba = UINT2RGBA(0x01010160);
671 Surf.PolyColor.s.alpha = (strength*8);
672 }
673 else // Do TRANSMAP** fade.
674 {
675 Surf.PolyColor.rgba = V_GetColor(color).rgba;
676 Surf.PolyColor.s.alpha = softwaretranstogl[strength];
677 }
678 HWD.pfnDrawPolygon(&Surf, v, 4, PF_NoTexture|PF_Modulated|PF_Translucent|PF_NoDepthTest);
679 }
680
681 // -----------------+
682 // HWR_DrawFadeFill : draw flat coloured rectangle, with transparency
683 // -----------------+
HWR_DrawFadeFill(INT32 x,INT32 y,INT32 w,INT32 h,INT32 color,UINT16 actualcolor,UINT8 strength)684 void HWR_DrawFadeFill(INT32 x, INT32 y, INT32 w, INT32 h, INT32 color, UINT16 actualcolor, UINT8 strength)
685 {
686 FOutVector v[4];
687 FSurfaceInfo Surf;
688 float fx, fy, fw, fh;
689
690 UINT8 perplayershuffle = 0;
691
692 // 3--2
693 // | /|
694 // |/ |
695 // 0--1
696
697 if (splitscreen && (color & V_PERPLAYER))
698 {
699 fixed_t adjusty = ((color & V_NOSCALESTART) ? vid.height : BASEVIDHEIGHT)/2.0f;
700 h >>= 1;
701 y >>= 1;
702 #ifdef QUADS
703 if (splitscreen > 1) // 3 or 4 players
704 {
705 fixed_t adjustx = ((color & V_NOSCALESTART) ? vid.height : BASEVIDHEIGHT)/2.0f;
706 w >>= 1;
707 x >>= 1;
708 if (stplyr == &players[displayplayer])
709 {
710 if (!(color & (V_SNAPTOTOP|V_SNAPTOBOTTOM)))
711 perplayershuffle |= 1;
712 if (!(color & (V_SNAPTOLEFT|V_SNAPTORIGHT)))
713 perplayershuffle |= 4;
714 color &= ~V_SNAPTOBOTTOM|V_SNAPTORIGHT;
715 }
716 else if (stplyr == &players[secondarydisplayplayer])
717 {
718 if (!(color & (V_SNAPTOTOP|V_SNAPTOBOTTOM)))
719 perplayershuffle |= 1;
720 if (!(color & (V_SNAPTOLEFT|V_SNAPTORIGHT)))
721 perplayershuffle |= 8;
722 x += adjustx;
723 color &= ~V_SNAPTOBOTTOM|V_SNAPTOLEFT;
724 }
725 else if (stplyr == &players[thirddisplayplayer])
726 {
727 if (!(color & (V_SNAPTOTOP|V_SNAPTOBOTTOM)))
728 perplayershuffle |= 2;
729 if (!(color & (V_SNAPTOLEFT|V_SNAPTORIGHT)))
730 perplayershuffle |= 4;
731 y += adjusty;
732 color &= ~V_SNAPTOTOP|V_SNAPTORIGHT;
733 }
734 else //if (stplyr == &players[fourthdisplayplayer])
735 {
736 if (!(color & (V_SNAPTOTOP|V_SNAPTOBOTTOM)))
737 perplayershuffle |= 2;
738 if (!(color & (V_SNAPTOLEFT|V_SNAPTORIGHT)))
739 perplayershuffle |= 8;
740 x += adjustx;
741 y += adjusty;
742 color &= ~V_SNAPTOTOP|V_SNAPTOLEFT;
743 }
744 }
745 else
746 #endif
747 // 2 players
748 {
749 if (stplyr == &players[displayplayer])
750 {
751 if (!(color & (V_SNAPTOTOP|V_SNAPTOBOTTOM)))
752 perplayershuffle |= 1;
753 color &= ~V_SNAPTOBOTTOM;
754 }
755 else //if (stplyr == &players[secondarydisplayplayer])
756 {
757 if (!(color & (V_SNAPTOTOP|V_SNAPTOBOTTOM)))
758 perplayershuffle |= 2;
759 y += adjusty;
760 color &= ~V_SNAPTOTOP;
761 }
762 }
763 }
764
765 fx = (float)x;
766 fy = (float)y;
767 fw = (float)w;
768 fh = (float)h;
769
770 if (!(color & V_NOSCALESTART))
771 {
772 float dupx = (float)vid.dupx, dupy = (float)vid.dupy;
773
774 fx *= dupx;
775 fy *= dupy;
776 fw *= dupx;
777 fh *= dupy;
778
779 if (fabsf((float)vid.width - (float)BASEVIDWIDTH * dupx) > 1.0E-36f)
780 {
781 if (color & V_SNAPTORIGHT)
782 fx += ((float)vid.width - ((float)BASEVIDWIDTH * dupx));
783 else if (!(color & V_SNAPTOLEFT))
784 fx += ((float)vid.width - ((float)BASEVIDWIDTH * dupx)) / 2;
785 if (perplayershuffle & 4)
786 fx -= ((float)vid.width - ((float)BASEVIDWIDTH * dupx)) / 4;
787 else if (perplayershuffle & 8)
788 fx += ((float)vid.width - ((float)BASEVIDWIDTH * dupx)) / 4;
789 }
790 if (fabsf((float)vid.height - (float)BASEVIDHEIGHT * dupy) > 1.0E-36f)
791 {
792 // same thing here
793 if (color & V_SNAPTOBOTTOM)
794 fy += ((float)vid.height - ((float)BASEVIDHEIGHT * dupy));
795 else if (!(color & V_SNAPTOTOP))
796 fy += ((float)vid.height - ((float)BASEVIDHEIGHT * dupy)) / 2;
797 if (perplayershuffle & 1)
798 fy -= ((float)vid.height - ((float)BASEVIDHEIGHT * dupy)) / 4;
799 else if (perplayershuffle & 2)
800 fy += ((float)vid.height - ((float)BASEVIDHEIGHT * dupy)) / 4;
801 }
802 }
803
804 if (fx >= vid.width || fy >= vid.height)
805 return;
806 if (fx < 0)
807 {
808 fw += fx;
809 fx = 0;
810 }
811 if (fy < 0)
812 {
813 fh += fy;
814 fy = 0;
815 }
816
817 if (fw <= 0 || fh <= 0)
818 return;
819 if (fx + fw > vid.width)
820 fw = (float)vid.width - fx;
821 if (fy + fh > vid.height)
822 fh = (float)vid.height - fy;
823
824 fx = -1 + fx / (vid.width / 2);
825 fy = 1 - fy / (vid.height / 2);
826 fw = fw / (vid.width / 2);
827 fh = fh / (vid.height / 2);
828
829 v[0].x = v[3].x = fx;
830 v[2].x = v[1].x = fx + fw;
831 v[0].y = v[1].y = fy;
832 v[2].y = v[3].y = fy - fh;
833
834 v[0].z = v[1].z = v[2].z = v[3].z = 1.0f;
835
836 v[0].s = v[3].s = 0.0f;
837 v[2].s = v[1].s = 1.0f;
838 v[0].t = v[1].t = 0.0f;
839 v[2].t = v[3].t = 1.0f;
840
841 if (actualcolor & 0xFF00) // Do COLORMAP fade.
842 {
843 Surf.PolyColor.rgba = UINT2RGBA(0x01010160);
844 Surf.PolyColor.s.alpha = (strength*8);
845 }
846 else // Do TRANSMAP** fade.
847 {
848 Surf.PolyColor.rgba = V_GetColor(actualcolor).rgba;
849 Surf.PolyColor.s.alpha = softwaretranstogl[strength];
850 }
851 HWD.pfnDrawPolygon(&Surf, v, 4, PF_NoTexture|PF_Modulated|PF_Translucent|PF_NoDepthTest);
852 }
853
854 // Draw the console background with translucency support
HWR_DrawConsoleBack(UINT32 color,INT32 height)855 void HWR_DrawConsoleBack(UINT32 color, INT32 height)
856 {
857 FOutVector v[4];
858 FSurfaceInfo Surf;
859
860 // setup some neat-o translucency effect
861 if (!height) //cool hack 0 height is full height
862 height = vid.height;
863
864 v[0].x = v[3].x = -1.0f;
865 v[2].x = v[1].x = 1.0f;
866 v[0].y = v[1].y = 1.0f-((height<<1)/(float)vid.height);
867 v[2].y = v[3].y = 1.0f;
868 v[0].z = v[1].z = v[2].z = v[3].z = 1.0f;
869
870 v[0].s = v[3].s = 0.0f;
871 v[2].s = v[1].s = 1.0f;
872 v[0].t = v[1].t = 1.0f;
873 v[2].t = v[3].t = 0.0f;
874
875 Surf.PolyColor.rgba = UINT2RGBA(color);
876 Surf.PolyColor.s.alpha = 0x80;
877
878 HWD.pfnDrawPolygon(&Surf, v, 4, PF_NoTexture|PF_Modulated|PF_Translucent|PF_NoDepthTest);
879 }
880
881 // Very similar to HWR_DrawConsoleBack, except we draw from the middle(-ish) of the screen to the bottom.
HWR_DrawTutorialBack(UINT32 color,INT32 boxheight)882 void HWR_DrawTutorialBack(UINT32 color, INT32 boxheight)
883 {
884 FOutVector v[4];
885 FSurfaceInfo Surf;
886 INT32 height;
887 if (boxheight < 0)
888 height = -boxheight;
889 else
890 height = (boxheight * 4) + (boxheight/2)*5; // 4 lines of space plus gaps between and some leeway
891
892 // setup some neat-o translucency effect
893
894 v[0].x = v[3].x = -1.0f;
895 v[2].x = v[1].x = 1.0f;
896 v[0].y = v[1].y = -1.0f;
897 v[2].y = v[3].y = -1.0f+((height<<1)/(float)vid.height);
898 v[0].z = v[1].z = v[2].z = v[3].z = 1.0f;
899
900 v[0].s = v[3].s = 0.0f;
901 v[2].s = v[1].s = 1.0f;
902 v[0].t = v[1].t = 1.0f;
903 v[2].t = v[3].t = 0.0f;
904
905 Surf.PolyColor.rgba = UINT2RGBA(color);
906 Surf.PolyColor.s.alpha = (color == 0 ? 0xC0 : 0x80); // make black darker, like software
907
908 HWD.pfnDrawPolygon(&Surf, v, 4, PF_NoTexture|PF_Modulated|PF_Translucent|PF_NoDepthTest);
909 }
910
911
912 // ==========================================================================
913 // R_DRAW.C STUFF
914 // ==========================================================================
915
916 // ------------------
917 // HWR_DrawViewBorder
918 // Fill the space around the view window with a Doom flat texture, draw the
919 // beveled edges.
920 // 'clearlines' is useful to clear the heads up messages, when the view
921 // window is reduced, it doesn't refresh all the view borders.
922 // ------------------
HWR_DrawViewBorder(INT32 clearlines)923 void HWR_DrawViewBorder(INT32 clearlines)
924 {
925 INT32 x, y;
926 INT32 top, side;
927 INT32 baseviewwidth, baseviewheight;
928 INT32 basewindowx, basewindowy;
929 patch_t *patch;
930
931 // if (gl_viewwidth == vid.width)
932 // return;
933
934 if (!clearlines)
935 clearlines = BASEVIDHEIGHT; // refresh all
936
937 // calc view size based on original game resolution
938 baseviewwidth = FixedInt(FixedDiv(FLOAT_TO_FIXED(gl_viewwidth), vid.fdupx)); //(cv_viewsize.value * BASEVIDWIDTH/10)&~7;
939 baseviewheight = FixedInt(FixedDiv(FLOAT_TO_FIXED(gl_viewheight), vid.fdupy));
940 top = FixedInt(FixedDiv(FLOAT_TO_FIXED(gl_baseviewwindowy), vid.fdupy));
941 side = FixedInt(FixedDiv(FLOAT_TO_FIXED(gl_viewwindowx), vid.fdupx));
942
943 // top
944 HWR_DrawFlatFill(0, 0,
945 BASEVIDWIDTH, (top < clearlines ? top : clearlines),
946 st_borderpatchnum);
947
948 // left
949 if (top < clearlines)
950 HWR_DrawFlatFill(0, top, side,
951 (clearlines-top < baseviewheight ? clearlines-top : baseviewheight),
952 st_borderpatchnum);
953
954 // right
955 if (top < clearlines)
956 HWR_DrawFlatFill(side + baseviewwidth, top, side,
957 (clearlines-top < baseviewheight ? clearlines-top : baseviewheight),
958 st_borderpatchnum);
959
960 // bottom
961 if (top + baseviewheight < clearlines)
962 HWR_DrawFlatFill(0, top + baseviewheight,
963 BASEVIDWIDTH, BASEVIDHEIGHT, st_borderpatchnum);
964
965 //
966 // draw the view borders
967 //
968
969 basewindowx = (BASEVIDWIDTH - baseviewwidth)>>1;
970 if (baseviewwidth == BASEVIDWIDTH)
971 basewindowy = 0;
972 else
973 basewindowy = top;
974
975 // top edge
976 if (clearlines > basewindowy - 8)
977 {
978 patch = W_CachePatchNum(viewborderlump[BRDR_T], PU_PATCH);
979 for (x = 0; x < baseviewwidth; x += 8)
980 HWR_DrawPatch(patch, basewindowx + x, basewindowy - 8,
981 0);
982 }
983
984 // bottom edge
985 if (clearlines > basewindowy + baseviewheight)
986 {
987 patch = W_CachePatchNum(viewborderlump[BRDR_B], PU_PATCH);
988 for (x = 0; x < baseviewwidth; x += 8)
989 HWR_DrawPatch(patch, basewindowx + x,
990 basewindowy + baseviewheight, 0);
991 }
992
993 // left edge
994 if (clearlines > basewindowy)
995 {
996 patch = W_CachePatchNum(viewborderlump[BRDR_L], PU_PATCH);
997 for (y = 0; y < baseviewheight && basewindowy + y < clearlines;
998 y += 8)
999 {
1000 HWR_DrawPatch(patch, basewindowx - 8, basewindowy + y,
1001 0);
1002 }
1003 }
1004
1005 // right edge
1006 if (clearlines > basewindowy)
1007 {
1008 patch = W_CachePatchNum(viewborderlump[BRDR_R], PU_PATCH);
1009 for (y = 0; y < baseviewheight && basewindowy+y < clearlines;
1010 y += 8)
1011 {
1012 HWR_DrawPatch(patch, basewindowx + baseviewwidth,
1013 basewindowy + y, 0);
1014 }
1015 }
1016
1017 // Draw beveled corners.
1018 if (clearlines > basewindowy - 8)
1019 HWR_DrawPatch(W_CachePatchNum(viewborderlump[BRDR_TL],
1020 PU_PATCH),
1021 basewindowx - 8, basewindowy - 8, 0);
1022
1023 if (clearlines > basewindowy - 8)
1024 HWR_DrawPatch(W_CachePatchNum(viewborderlump[BRDR_TR],
1025 PU_PATCH),
1026 basewindowx + baseviewwidth, basewindowy - 8, 0);
1027
1028 if (clearlines > basewindowy+baseviewheight)
1029 HWR_DrawPatch(W_CachePatchNum(viewborderlump[BRDR_BL],
1030 PU_PATCH),
1031 basewindowx - 8, basewindowy + baseviewheight, 0);
1032
1033 if (clearlines > basewindowy + baseviewheight)
1034 HWR_DrawPatch(W_CachePatchNum(viewborderlump[BRDR_BR],
1035 PU_PATCH),
1036 basewindowx + baseviewwidth,
1037 basewindowy + baseviewheight, 0);
1038 }
1039
1040
1041 // ==========================================================================
1042 // AM_MAP.C DRAWING STUFF
1043 // ==========================================================================
1044
1045 // -----------------+
1046 // HWR_drawAMline : draw a line of the automap (the clipping is already done in automap code)
1047 // Arg : color is a RGB 888 value
1048 // -----------------+
HWR_drawAMline(const fline_t * fl,INT32 color)1049 void HWR_drawAMline(const fline_t *fl, INT32 color)
1050 {
1051 F2DCoord v1, v2;
1052 RGBA_t color_rgba;
1053
1054 color_rgba = V_GetColor(color);
1055
1056 v1.x = ((float)fl->a.x-(vid.width/2.0f))*(2.0f/vid.width);
1057 v1.y = ((float)fl->a.y-(vid.height/2.0f))*(2.0f/vid.height);
1058
1059 v2.x = ((float)fl->b.x-(vid.width/2.0f))*(2.0f/vid.width);
1060 v2.y = ((float)fl->b.y-(vid.height/2.0f))*(2.0f/vid.height);
1061
1062 HWD.pfnDraw2DLine(&v1, &v2, color_rgba);
1063 }
1064
1065 // -------------------+
1066 // HWR_DrawConsoleFill : draw flat coloured transparent rectangle because that's cool, and hw sucks less than sw for that.
1067 // -------------------+
HWR_DrawConsoleFill(INT32 x,INT32 y,INT32 w,INT32 h,INT32 color,UINT32 actualcolor)1068 void HWR_DrawConsoleFill(INT32 x, INT32 y, INT32 w, INT32 h, INT32 color, UINT32 actualcolor)
1069 {
1070 FOutVector v[4];
1071 FSurfaceInfo Surf;
1072 float fx, fy, fw, fh;
1073
1074 UINT8 perplayershuffle = 0;
1075
1076 // 3--2
1077 // | /|
1078 // |/ |
1079 // 0--1
1080
1081 if (splitscreen && (color & V_PERPLAYER))
1082 {
1083 fixed_t adjusty = ((color & V_NOSCALESTART) ? vid.height : BASEVIDHEIGHT)/2.0f;
1084 h >>= 1;
1085 y >>= 1;
1086 #ifdef QUADS
1087 if (splitscreen > 1) // 3 or 4 players
1088 {
1089 fixed_t adjustx = ((color & V_NOSCALESTART) ? vid.height : BASEVIDHEIGHT)/2.0f;
1090 w >>= 1;
1091 x >>= 1;
1092 if (stplyr == &players[displayplayer])
1093 {
1094 if (!(color & (V_SNAPTOTOP|V_SNAPTOBOTTOM)))
1095 perplayershuffle |= 1;
1096 if (!(color & (V_SNAPTOLEFT|V_SNAPTORIGHT)))
1097 perplayershuffle |= 4;
1098 color &= ~V_SNAPTOBOTTOM|V_SNAPTORIGHT;
1099 }
1100 else if (stplyr == &players[secondarydisplayplayer])
1101 {
1102 if (!(color & (V_SNAPTOTOP|V_SNAPTOBOTTOM)))
1103 perplayershuffle |= 1;
1104 if (!(color & (V_SNAPTOLEFT|V_SNAPTORIGHT)))
1105 perplayershuffle |= 8;
1106 x += adjustx;
1107 color &= ~V_SNAPTOBOTTOM|V_SNAPTOLEFT;
1108 }
1109 else if (stplyr == &players[thirddisplayplayer])
1110 {
1111 if (!(color & (V_SNAPTOTOP|V_SNAPTOBOTTOM)))
1112 perplayershuffle |= 2;
1113 if (!(color & (V_SNAPTOLEFT|V_SNAPTORIGHT)))
1114 perplayershuffle |= 4;
1115 y += adjusty;
1116 color &= ~V_SNAPTOTOP|V_SNAPTORIGHT;
1117 }
1118 else //if (stplyr == &players[fourthdisplayplayer])
1119 {
1120 if (!(color & (V_SNAPTOTOP|V_SNAPTOBOTTOM)))
1121 perplayershuffle |= 2;
1122 if (!(color & (V_SNAPTOLEFT|V_SNAPTORIGHT)))
1123 perplayershuffle |= 8;
1124 x += adjustx;
1125 y += adjusty;
1126 color &= ~V_SNAPTOTOP|V_SNAPTOLEFT;
1127 }
1128 }
1129 else
1130 #endif
1131 // 2 players
1132 {
1133 if (stplyr == &players[displayplayer])
1134 {
1135 if (!(color & (V_SNAPTOTOP|V_SNAPTOBOTTOM)))
1136 perplayershuffle |= 1;
1137 color &= ~V_SNAPTOBOTTOM;
1138 }
1139 else //if (stplyr == &players[secondarydisplayplayer])
1140 {
1141 if (!(color & (V_SNAPTOTOP|V_SNAPTOBOTTOM)))
1142 perplayershuffle |= 2;
1143 y += adjusty;
1144 color &= ~V_SNAPTOTOP;
1145 }
1146 }
1147 }
1148
1149 fx = (float)x;
1150 fy = (float)y;
1151 fw = (float)w;
1152 fh = (float)h;
1153
1154 if (!(color & V_NOSCALESTART))
1155 {
1156 float dupx = (float)vid.dupx, dupy = (float)vid.dupy;
1157
1158 fx *= dupx;
1159 fy *= dupy;
1160 fw *= dupx;
1161 fh *= dupy;
1162
1163 if (fabsf((float)vid.width - (float)BASEVIDWIDTH * dupx) > 1.0E-36f)
1164 {
1165 if (color & V_SNAPTORIGHT)
1166 fx += ((float)vid.width - ((float)BASEVIDWIDTH * dupx));
1167 else if (!(color & V_SNAPTOLEFT))
1168 fx += ((float)vid.width - ((float)BASEVIDWIDTH * dupx)) / 2;
1169 if (perplayershuffle & 4)
1170 fx -= ((float)vid.width - ((float)BASEVIDWIDTH * dupx)) / 4;
1171 else if (perplayershuffle & 8)
1172 fx += ((float)vid.width - ((float)BASEVIDWIDTH * dupx)) / 4;
1173 }
1174 if (fabsf((float)vid.height - (float)BASEVIDHEIGHT * dupy) > 1.0E-36f)
1175 {
1176 // same thing here
1177 if (color & V_SNAPTOBOTTOM)
1178 fy += ((float)vid.height - ((float)BASEVIDHEIGHT * dupy));
1179 else if (!(color & V_SNAPTOTOP))
1180 fy += ((float)vid.height - ((float)BASEVIDHEIGHT * dupy)) / 2;
1181 if (perplayershuffle & 1)
1182 fy -= ((float)vid.height - ((float)BASEVIDHEIGHT * dupy)) / 4;
1183 else if (perplayershuffle & 2)
1184 fy += ((float)vid.height - ((float)BASEVIDHEIGHT * dupy)) / 4;
1185 }
1186 }
1187
1188 if (fx >= vid.width || fy >= vid.height)
1189 return;
1190 if (fx < 0)
1191 {
1192 fw += fx;
1193 fx = 0;
1194 }
1195 if (fy < 0)
1196 {
1197 fh += fy;
1198 fy = 0;
1199 }
1200
1201 if (fw <= 0 || fh <= 0)
1202 return;
1203 if (fx + fw > vid.width)
1204 fw = (float)vid.width - fx;
1205 if (fy + fh > vid.height)
1206 fh = (float)vid.height - fy;
1207
1208 fx = -1 + fx / (vid.width / 2);
1209 fy = 1 - fy / (vid.height / 2);
1210 fw = fw / (vid.width / 2);
1211 fh = fh / (vid.height / 2);
1212
1213 v[0].x = v[3].x = fx;
1214 v[2].x = v[1].x = fx + fw;
1215 v[0].y = v[1].y = fy;
1216 v[2].y = v[3].y = fy - fh;
1217
1218 v[0].z = v[1].z = v[2].z = v[3].z = 1.0f;
1219
1220 v[0].s = v[3].s = 0.0f;
1221 v[2].s = v[1].s = 1.0f;
1222 v[0].t = v[1].t = 0.0f;
1223 v[2].t = v[3].t = 1.0f;
1224
1225 Surf.PolyColor.rgba = UINT2RGBA(actualcolor);
1226 Surf.PolyColor.s.alpha = 0x80;
1227
1228 HWD.pfnDrawPolygon(&Surf, v, 4, PF_NoTexture|PF_Modulated|PF_Translucent|PF_NoDepthTest);
1229 }
1230
1231 // -----------------+
1232 // HWR_DrawFill : draw flat coloured rectangle, with no texture
1233 // -----------------+
HWR_DrawFill(INT32 x,INT32 y,INT32 w,INT32 h,INT32 color)1234 void HWR_DrawFill(INT32 x, INT32 y, INT32 w, INT32 h, INT32 color)
1235 {
1236 FOutVector v[4];
1237 FSurfaceInfo Surf;
1238 float fx, fy, fw, fh;
1239
1240 UINT8 perplayershuffle = 0;
1241
1242 // 3--2
1243 // | /|
1244 // |/ |
1245 // 0--1
1246
1247 if (splitscreen && (color & V_PERPLAYER))
1248 {
1249 fixed_t adjusty = ((color & V_NOSCALESTART) ? vid.height : BASEVIDHEIGHT)/2.0f;
1250 h >>= 1;
1251 y >>= 1;
1252 #ifdef QUADS
1253 if (splitscreen > 1) // 3 or 4 players
1254 {
1255 fixed_t adjustx = ((color & V_NOSCALESTART) ? vid.height : BASEVIDHEIGHT)/2.0f;
1256 w >>= 1;
1257 x >>= 1;
1258 if (stplyr == &players[displayplayer])
1259 {
1260 if (!(color & (V_SNAPTOTOP|V_SNAPTOBOTTOM)))
1261 perplayershuffle |= 1;
1262 if (!(color & (V_SNAPTOLEFT|V_SNAPTORIGHT)))
1263 perplayershuffle |= 4;
1264 color &= ~V_SNAPTOBOTTOM|V_SNAPTORIGHT;
1265 }
1266 else if (stplyr == &players[secondarydisplayplayer])
1267 {
1268 if (!(color & (V_SNAPTOTOP|V_SNAPTOBOTTOM)))
1269 perplayershuffle |= 1;
1270 if (!(color & (V_SNAPTOLEFT|V_SNAPTORIGHT)))
1271 perplayershuffle |= 8;
1272 x += adjustx;
1273 color &= ~V_SNAPTOBOTTOM|V_SNAPTOLEFT;
1274 }
1275 else if (stplyr == &players[thirddisplayplayer])
1276 {
1277 if (!(color & (V_SNAPTOTOP|V_SNAPTOBOTTOM)))
1278 perplayershuffle |= 2;
1279 if (!(color & (V_SNAPTOLEFT|V_SNAPTORIGHT)))
1280 perplayershuffle |= 4;
1281 y += adjusty;
1282 color &= ~V_SNAPTOTOP|V_SNAPTORIGHT;
1283 }
1284 else //if (stplyr == &players[fourthdisplayplayer])
1285 {
1286 if (!(color & (V_SNAPTOTOP|V_SNAPTOBOTTOM)))
1287 perplayershuffle |= 2;
1288 if (!(color & (V_SNAPTOLEFT|V_SNAPTORIGHT)))
1289 perplayershuffle |= 8;
1290 x += adjustx;
1291 y += adjusty;
1292 color &= ~V_SNAPTOTOP|V_SNAPTOLEFT;
1293 }
1294 }
1295 else
1296 #endif
1297 // 2 players
1298 {
1299 if (stplyr == &players[displayplayer])
1300 {
1301 if (!(color & (V_SNAPTOTOP|V_SNAPTOBOTTOM)))
1302 perplayershuffle |= 1;
1303 color &= ~V_SNAPTOBOTTOM;
1304 }
1305 else //if (stplyr == &players[secondarydisplayplayer])
1306 {
1307 if (!(color & (V_SNAPTOTOP|V_SNAPTOBOTTOM)))
1308 perplayershuffle |= 2;
1309 y += adjusty;
1310 color &= ~V_SNAPTOTOP;
1311 }
1312 }
1313 }
1314
1315 fx = (float)x;
1316 fy = (float)y;
1317 fw = (float)w;
1318 fh = (float)h;
1319
1320 if (!(color & V_NOSCALESTART))
1321 {
1322 float dupx = (float)vid.dupx, dupy = (float)vid.dupy;
1323
1324 if (x == 0 && y == 0 && w == BASEVIDWIDTH && h == BASEVIDHEIGHT)
1325 {
1326 RGBA_t rgbaColour = V_GetColor(color);
1327 FRGBAFloat clearColour;
1328 clearColour.red = (float)rgbaColour.s.red / 255;
1329 clearColour.green = (float)rgbaColour.s.green / 255;
1330 clearColour.blue = (float)rgbaColour.s.blue / 255;
1331 clearColour.alpha = 1;
1332 HWD.pfnClearBuffer(true, false, &clearColour);
1333 return;
1334 }
1335
1336 fx *= dupx;
1337 fy *= dupy;
1338 fw *= dupx;
1339 fh *= dupy;
1340
1341 if (fabsf((float)vid.width - (float)BASEVIDWIDTH * dupx) > 1.0E-36f)
1342 {
1343 if (color & V_SNAPTORIGHT)
1344 fx += ((float)vid.width - ((float)BASEVIDWIDTH * dupx));
1345 else if (!(color & V_SNAPTOLEFT))
1346 fx += ((float)vid.width - ((float)BASEVIDWIDTH * dupx)) / 2;
1347 if (perplayershuffle & 4)
1348 fx -= ((float)vid.width - ((float)BASEVIDWIDTH * dupx)) / 4;
1349 else if (perplayershuffle & 8)
1350 fx += ((float)vid.width - ((float)BASEVIDWIDTH * dupx)) / 4;
1351 }
1352 if (fabsf((float)vid.height - (float)BASEVIDHEIGHT * dupy) > 1.0E-36f)
1353 {
1354 // same thing here
1355 if (color & V_SNAPTOBOTTOM)
1356 fy += ((float)vid.height - ((float)BASEVIDHEIGHT * dupy));
1357 else if (!(color & V_SNAPTOTOP))
1358 fy += ((float)vid.height - ((float)BASEVIDHEIGHT * dupy)) / 2;
1359 if (perplayershuffle & 1)
1360 fy -= ((float)vid.height - ((float)BASEVIDHEIGHT * dupy)) / 4;
1361 else if (perplayershuffle & 2)
1362 fy += ((float)vid.height - ((float)BASEVIDHEIGHT * dupy)) / 4;
1363 }
1364 }
1365
1366 if (fx >= vid.width || fy >= vid.height)
1367 return;
1368 if (fx < 0)
1369 {
1370 fw += fx;
1371 fx = 0;
1372 }
1373 if (fy < 0)
1374 {
1375 fh += fy;
1376 fy = 0;
1377 }
1378
1379 if (fw <= 0 || fh <= 0)
1380 return;
1381 if (fx + fw > vid.width)
1382 fw = (float)vid.width - fx;
1383 if (fy + fh > vid.height)
1384 fh = (float)vid.height - fy;
1385
1386 fx = -1 + fx / (vid.width / 2);
1387 fy = 1 - fy / (vid.height / 2);
1388 fw = fw / (vid.width / 2);
1389 fh = fh / (vid.height / 2);
1390
1391 v[0].x = v[3].x = fx;
1392 v[2].x = v[1].x = fx + fw;
1393 v[0].y = v[1].y = fy;
1394 v[2].y = v[3].y = fy - fh;
1395
1396 v[0].z = v[1].z = v[2].z = v[3].z = 1.0f;
1397
1398 v[0].s = v[3].s = 0.0f;
1399 v[2].s = v[1].s = 1.0f;
1400 v[0].t = v[1].t = 0.0f;
1401 v[2].t = v[3].t = 1.0f;
1402
1403 Surf.PolyColor = V_GetColor(color);
1404
1405 HWD.pfnDrawPolygon(&Surf, v, 4,
1406 PF_Modulated|PF_NoTexture|PF_NoDepthTest);
1407 }
1408
1409 #ifdef HAVE_PNG
1410
1411 #ifndef _MSC_VER
1412 #ifndef _LARGEFILE64_SOURCE
1413 #define _LARGEFILE64_SOURCE
1414 #endif
1415 #endif
1416
1417 #ifndef _LFS64_LARGEFILE
1418 #define _LFS64_LARGEFILE
1419 #endif
1420
1421 #ifndef _FILE_OFFSET_BITS
1422 #define _FILE_OFFSET_BITS 0
1423 #endif
1424
1425 #include "png.h"
1426 #ifdef PNG_WRITE_SUPPORTED
1427 #define USE_PNG // PNG is only used if write is supported (see ../m_misc.c)
1428 #endif
1429 #endif
1430
1431 #ifndef USE_PNG
1432 // --------------------------------------------------------------------------
1433 // save screenshots with TGA format
1434 // --------------------------------------------------------------------------
saveTGA(const char * file_name,void * buffer,INT32 width,INT32 height)1435 static inline boolean saveTGA(const char *file_name, void *buffer,
1436 INT32 width, INT32 height)
1437 {
1438 INT32 fd;
1439 TGAHeader tga_hdr;
1440 INT32 i;
1441 UINT8 *buf8 = buffer;
1442
1443 fd = open(file_name, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, 0666);
1444 if (fd < 0)
1445 return false;
1446
1447 memset(&tga_hdr, 0, sizeof (tga_hdr));
1448 tga_hdr.width = SHORT(width);
1449 tga_hdr.height = SHORT(height);
1450 tga_hdr.image_pix_size = 24;
1451 tga_hdr.image_type = 2;
1452 tga_hdr.image_descriptor = 32;
1453
1454 if ( -1 == write(fd, &tga_hdr, sizeof (TGAHeader)))
1455 {
1456 close(fd);
1457 return false;
1458 }
1459 // format to 888 BGR
1460 for (i = 0; i < width * height * 3; i+=3)
1461 {
1462 const UINT8 temp = buf8[i];
1463 buf8[i] = buf8[i+2];
1464 buf8[i+2] = temp;
1465 }
1466 if ( -1 == write(fd, buffer, width * height * 3))
1467 {
1468 close(fd);
1469 return false;
1470 }
1471 close(fd);
1472 return true;
1473 }
1474 #endif
1475
1476 // --------------------------------------------------------------------------
1477 // screen shot
1478 // --------------------------------------------------------------------------
1479
HWR_GetScreenshot(void)1480 UINT8 *HWR_GetScreenshot(void)
1481 {
1482 UINT8 *buf = malloc(vid.width * vid.height * 3 * sizeof (*buf));
1483
1484 if (!buf)
1485 return NULL;
1486 // returns 24bit 888 RGB
1487 HWD.pfnReadRect(0, 0, vid.width, vid.height, vid.width * 3, (void *)buf);
1488 return buf;
1489 }
1490
HWR_Screenshot(const char * pathname)1491 boolean HWR_Screenshot(const char *pathname)
1492 {
1493 boolean ret;
1494 UINT8 *buf = malloc(vid.width * vid.height * 3 * sizeof (*buf));
1495
1496 if (!buf)
1497 {
1498 CONS_Debug(DBG_RENDER, "HWR_Screenshot: Failed to allocate memory\n");
1499 return false;
1500 }
1501
1502 // returns 24bit 888 RGB
1503 HWD.pfnReadRect(0, 0, vid.width, vid.height, vid.width * 3, (void *)buf);
1504
1505 #ifdef USE_PNG
1506 ret = M_SavePNG(pathname, buf, vid.width, vid.height, NULL);
1507 #else
1508 ret = saveTGA(pathname, buf, vid.width, vid.height);
1509 #endif
1510 free(buf);
1511 return ret;
1512 }
1513
1514 #endif //HWRENDER
1515