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