1 //**************************************************************************
2 //**
3 //**	##   ##    ##    ##   ##   ####     ####   ###     ###
4 //**	##   ##  ##  ##  ##   ##  ##  ##   ##  ##  ####   ####
5 //**	 ## ##  ##    ##  ## ##  ##    ## ##    ## ## ## ## ##
6 //**	 ## ##  ########  ## ##  ##    ## ##    ## ##  ###  ##
7 //**	  ###   ##    ##   ###    ##  ##   ##  ##  ##       ##
8 //**	   #    ##    ##    #      ####     ####   ##       ##
9 //**
10 //**	$Id: r_things.cpp 4355 2010-12-24 01:29:15Z firebrand_kh $
11 //**
12 //**	Copyright (C) 1999-2006 Jānis Legzdiņš
13 //**
14 //**	This program is free software; you can redistribute it and/or
15 //**  modify it under the terms of the GNU General Public License
16 //**  as published by the Free Software Foundation; either version 2
17 //**  of the License, or (at your option) any later version.
18 //**
19 //**	This program is distributed in the hope that it will be useful,
20 //**  but WITHOUT ANY WARRANTY; without even the implied warranty of
21 //**  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
22 //**  GNU General Public License for more details.
23 //**
24 //**************************************************************************
25 //**
26 //**	Refresh of things, i.e. objects represented by sprites.
27 //**
28 //** 	Sprite rotation 0 is facing the viewer, rotation 1 is one angle turn
29 //**  CLOCKWISE around the axis. This is not the same as the angle, which
30 //**  increases counter clockwise (protractor). There was a lot of stuff
31 //**  grabbed wrong, so I changed it...
32 //**
33 //**************************************************************************
34 
35 // HEADER FILES ------------------------------------------------------------
36 
37 #include "gamedefs.h"
38 #include "r_local.h"
39 #include "sv_local.h"
40 
41 // MACROS ------------------------------------------------------------------
42 
43 // TYPES -------------------------------------------------------------------
44 
45 enum
46 {
47 	SPR_VP_PARALLEL_UPRIGHT,
48 	SPR_FACING_UPRIGHT,
49 	SPR_VP_PARALLEL,
50 	SPR_ORIENTED,
51 	SPR_VP_PARALLEL_ORIENTED,
52 	SPR_VP_PARALLEL_UPRIGHT_ORIENTED,
53 };
54 
55 // EXTERNAL FUNCTION PROTOTYPES --------------------------------------------
56 
57 // PUBLIC FUNCTION PROTOTYPES ----------------------------------------------
58 
59 // PRIVATE FUNCTION PROTOTYPES ---------------------------------------------
60 
61 // EXTERNAL DATA DECLARATIONS ----------------------------------------------
62 
63 extern VCvarI		r_chasecam;
64 
65 // PUBLIC DATA DEFINITIONS -------------------------------------------------
66 
67 // PRIVATE DATA DEFINITIONS ------------------------------------------------
68 
69 VCvarI			r_draw_mobjs("r_draw_mobjs", "1", CVAR_Archive);
70 VCvarI			r_draw_psprites("r_draw_psprites", "1", CVAR_Archive);
71 VCvarI			r_models("r_models", "1", CVAR_Archive);
72 VCvarI			r_hide_models("r_hide_models", "0", CVAR_Archive);
73 VCvarI			r_view_models("r_view_models", "1", CVAR_Archive);
74 VCvarI			r_model_shadows("r_model_shadows", "1", CVAR_Archive);
75 VCvarI			r_model_light("r_model_light", "1", CVAR_Archive);
76 VCvarI			r_sort_sprites("r_sort_sprites", "0");
77 VCvarI			r_fix_sprite_offsets("r_fix_sprite_offsets", "1", CVAR_Archive);
78 VCvarI			r_sprite_fix_delta("r_sprite_fix_delta", "-3", CVAR_Archive);
79 VCvarI			r_drawfuzz("r_drawfuzz", "1", CVAR_Archive);
80 VCvarF			transsouls("transsouls", "1.0", CVAR_Archive);
81 VCvarI			croshair("croshair", "0", CVAR_Archive);
82 VCvarF			croshair_alpha("croshair_alpha", "1", CVAR_Archive);
83 
84 // CODE --------------------------------------------------------------------
85 
86 //==========================================================================
87 //
88 //	VRenderLevelShared::DrawTranslucentPoly
89 //
90 //==========================================================================
91 
DrawTranslucentPoly(surface_t * surf,TVec * sv,int count,int lump,float Alpha,bool Additive,int translation,bool type,vuint32 light,vuint32 Fade,const TVec & normal,float pdist,const TVec & saxis,const TVec & taxis,const TVec & texorg)92 void VRenderLevelShared::DrawTranslucentPoly(surface_t* surf, TVec* sv,
93 	int count, int lump, float Alpha, bool Additive, int translation,
94 	bool type, vuint32 light, vuint32 Fade, const TVec& normal, float pdist,
95 	const TVec& saxis, const TVec& taxis, const TVec& texorg)
96 {
97 	guard(VRenderLevelShared::DrawTranslucentPoly);
98 	int i;
99 
100 	TVec mid(0, 0, 0);
101 	for (i = 0; i < count; i++)
102 	{
103 		mid += sv[i];
104 	}
105 	mid /= count;
106 	float dist = fabs(DotProduct(mid - vieworg, viewforward));
107 //	float dist = Length(mid - vieworg);
108 	int found = -1;
109 	float best_dist = -1;
110 	for (i = 0; i < MAX_TRANS_SPRITES; i++)
111 	{
112 		trans_sprite_t &spr = trans_sprites[i];
113 		if (!spr.Alpha)
114 		{
115 			if (type)
116 				memcpy(spr.Verts, sv, sizeof(TVec) * 4);
117 			spr.dist = dist;
118 			spr.lump = lump;
119 			spr.normal = normal;
120 			spr.pdist = pdist;
121 			spr.saxis = saxis;
122 			spr.taxis = taxis;
123 			spr.texorg = texorg;
124 			spr.surf = surf;
125 			spr.Alpha = Alpha;
126 			spr.Additive = Additive;
127 			spr.translation = translation;
128 			spr.type = type;
129 			spr.light = light;
130 			spr.Fade = Fade;
131 			return;
132 		}
133 		if (spr.dist > best_dist)
134 		{
135 			found = i;
136 			best_dist = spr.dist;
137 		}
138 	}
139 	if (best_dist > dist)
140 	{
141 		//	All slots are full, draw and replace a far away sprite
142 		trans_sprite_t &spr = trans_sprites[found];
143 		if (spr.type == 2)
144 		{
145 			DrawEntityModel(spr.Ent, spr.light, spr.Fade, spr.Alpha,
146 				spr.Additive, spr.TimeFrac, RPASS_Normal);
147 		}
148 		else if (spr.type)
149 		{
150 			Drawer->DrawSpritePolygon(spr.Verts, GTextureManager[spr.lump],
151 				spr.Alpha, spr.Additive, GetTranslation(spr.translation),
152 				ColourMap, spr.light, spr.Fade, spr.normal, spr.pdist,
153 				spr.saxis, spr.taxis, spr.texorg);
154 		}
155 		else
156 		{
157 			check(spr.surf);
158 			Drawer->DrawMaskedPolygon(spr.surf, spr.Alpha, spr.Additive);
159 		}
160 		if (type)
161 			memcpy(spr.Verts, sv, sizeof(TVec) * 4);
162 		spr.dist = dist;
163 		spr.lump = lump;
164 		spr.normal = normal;
165 		spr.pdist = pdist;
166 		spr.saxis = saxis;
167 		spr.taxis = taxis;
168 		spr.texorg = texorg;
169 		spr.surf = surf;
170 		spr.Alpha = Alpha;
171 		spr.Additive = Additive;
172 		spr.translation = translation;
173 		spr.type = type;
174 		spr.light = light;
175 		spr.Fade = Fade;
176 		return;
177 	}
178 
179 	//	All slots are full and are nearer to current sprite so draw it
180 	if (type)
181 	{
182 		Drawer->DrawSpritePolygon(sv, GTextureManager[lump], Alpha,
183 			Additive, GetTranslation(translation), ColourMap, light, Fade,
184 			normal, pdist, saxis, taxis, texorg);
185 	}
186 	else
187 	{
188 		check(surf);
189 		Drawer->DrawMaskedPolygon(surf, Alpha, Additive);
190 	}
191 	unguard;
192 }
193 
194 //==========================================================================
195 //
196 //	VRenderLevelShared::RenderSprite
197 //
198 //==========================================================================
199 
RenderSprite(VEntity * thing,vuint32 light,vuint32 Fade,float Alpha,bool Additive)200 void VRenderLevelShared::RenderSprite(VEntity* thing, vuint32 light,
201 	vuint32 Fade, float Alpha, bool Additive)
202 {
203 	guard(VRenderLevelShared::RenderSprite);
204 	int spr_type = thing->SpriteType;
205 
206 	TVec sprorigin = thing->Origin;
207 	sprorigin.z -= thing->FloorClip;
208 	TVec sprforward;
209 	TVec sprright;
210 	TVec sprup;
211 
212 	float		dot;
213 	TVec		tvec;
214 	float		sr;
215 	float		cr;
216 
217 	switch (spr_type)
218 	{
219 	case SPR_VP_PARALLEL_UPRIGHT:
220 		//	Generate the sprite's axes, with sprup straight up in worldspace,
221 		// and sprright parallel to the viewplane. This will not work if the
222 		// view direction is very close to straight up or down, because the
223 		// cross product will be between two nearly parallel vectors and
224 		// starts to approach an undefined state, so we don't draw if the two
225 		// vectors are less than 1 degree apart
226 		dot = viewforward.z;	//	same as DotProduct(viewforward, sprup)
227 								// because sprup is 0, 0, 1
228 		if ((dot > 0.999848) || (dot < -0.999848))	// cos(1 degree) = 0.999848
229 			return;
230 
231 		sprup = TVec(0, 0, 1);
232 		//	CrossProduct(sprup, viewforward)
233 		sprright = Normalise(TVec(viewforward.y, -viewforward.x, 0));
234 		//	CrossProduct(sprright, sprup)
235 		sprforward = TVec(-sprright.y, sprright.x, 0);
236 		break;
237 
238 	case SPR_FACING_UPRIGHT:
239 		//	Generate the sprite's axes, with sprup straight up in worldspace,
240 		// and sprright perpendicular to sprorigin. This will not work if the
241 		// view direction is very close to straight up or down, because the
242 		// cross product will be between two nearly parallel vectors and
243 		// starts to approach an undefined state, so we don't draw if the two
244 		// vectors are less than 1 degree apart
245 		tvec = Normalise(sprorigin - vieworg);
246 		dot = tvec.z;	//	same as DotProduct (tvec, sprup) because
247 						// sprup is 0, 0, 1
248 		if ((dot > 0.999848) || (dot < -0.999848))	// cos(1 degree) = 0.999848
249 			return;
250 		sprup = TVec(0, 0, 1);
251 		//	CrossProduct(sprup, -sprorigin)
252 		sprright = Normalise(TVec(tvec.y, -tvec.x, 0));
253 		//	CrossProduct(sprright, sprup)
254 		sprforward = TVec(-sprright.y, sprright.x, 0);
255 		break;
256 
257 	case SPR_VP_PARALLEL:
258 		//	Generate the sprite's axes, completely parallel to the viewplane.
259 		// There are no problem situations, because the sprite is always in
260 		// the same position relative to the viewer
261 		sprup = viewup;
262 		sprright = viewright;
263 		sprforward = viewforward;
264 		break;
265 
266 	case SPR_ORIENTED:
267 		//	Generate the sprite's axes, according to the sprite's world
268 		// orientation
269 		AngleVectors(thing->Angles, sprforward, sprright, sprup);
270 		break;
271 
272 	case SPR_VP_PARALLEL_ORIENTED:
273 		//	Generate the sprite's axes, parallel to the viewplane, but
274 		// rotated in that plane around the centre according to the sprite
275 		// entity's roll angle. So sprforward stays the same, but sprright
276 		// and sprup rotate
277 		sr = msin(thing->Angles.roll);
278 		cr = mcos(thing->Angles.roll);
279 
280 		sprforward = viewforward;
281 		sprright = TVec(viewright.x * cr + viewup.x * sr, viewright.y * cr +
282 			viewup.y * sr, viewright.z * cr + viewup.z * sr);
283 		sprup = TVec(viewright.x * -sr + viewup.x * cr, viewright.y * -sr +
284 			viewup.y * cr, viewright.z * -sr + viewup.z * cr);
285 		break;
286 
287 	case SPR_VP_PARALLEL_UPRIGHT_ORIENTED:
288 		//	Generate the sprite's axes, with sprup straight up in worldspace,
289 		// and sprright parallel to the viewplane and then rotated in that
290 		// plane around the centre according to the sprite entity's roll
291 		// angle. So sprforward stays the same, but sprright and sprup rotate
292 		// This will not work if the view direction is very close to straight
293 		// up or down, because the cross product will be between two nearly
294 		// parallel vectors and starts to approach an undefined state, so we
295 		// don't draw if the two vectors are less than 1 degree apart
296 		dot = viewforward.z;	//	same as DotProduct(viewforward, sprup)
297 								// because sprup is 0, 0, 1
298 		if ((dot > 0.999848) || (dot < -0.999848))	// cos(1 degree) = 0.999848
299 			return;
300 
301 		sr = msin(thing->Angles.roll);
302 		cr = mcos(thing->Angles.roll);
303 
304 		//	CrossProduct(TVec(0, 0, 1), viewforward)
305 		tvec = Normalise(TVec(viewforward.y, -viewforward.x, 0));
306 		//	CrossProduct(tvec, TVec(0, 0, 1))
307 		sprforward = TVec(-tvec.y, tvec.x, 0);
308 		//	Rotate
309 		sprright = TVec(tvec.x * cr, tvec.y * cr, tvec.z * cr + sr);
310 		sprup = TVec(tvec.x * -sr, tvec.y * -sr, tvec.z * -sr + cr);
311 		break;
312 
313 	default:
314 		Sys_Error("RenderSprite: Bad sprite type %d", spr_type);
315 	}
316 
317 	spritedef_t*	sprdef;
318 	spriteframe_t*	sprframe;
319 
320 	VState* DispState = (thing->EntityFlags & VEntity::EF_UseDispState) ?
321 		thing->DispState : thing->State;
322 	int SpriteIndex = DispState->SpriteIndex;
323 	if (thing->FixedSpriteName != NAME_None)
324 	{
325 		SpriteIndex = VClass::FindSprite(thing->FixedSpriteName);
326 	}
327 
328 	// decide which patch to use for sprite relative to player
329 	if ((unsigned)SpriteIndex >= MAX_SPRITE_MODELS)
330 	{
331 #ifdef PARANOID
332 		GCon->Logf(NAME_Dev, "Invalid sprite number %d", SpriteIndex);
333 #endif
334 		return;
335 	}
336 	sprdef = &sprites[SpriteIndex];
337 	if ((DispState->Frame & VState::FF_FRAMEMASK) >= sprdef->numframes)
338 	{
339 #ifdef PARANOID
340 		GCon->Logf(NAME_Dev, "Invalid sprite frame %d : %d",
341 			SpriteIndex, DispState->Frame);
342 #endif
343 		return;
344 	}
345 	sprframe = &sprdef->spriteframes[DispState->Frame & VState::FF_FRAMEMASK];
346 
347 	int			lump;
348 	bool		flip;
349 
350 	if (sprframe->rotate)
351 	{
352 		// choose a different rotation based on player view
353 		//FIXME must use sprforward here?
354 		float ang = matan(thing->Origin.y - vieworg.y,
355 			thing->Origin.x - vieworg.x);
356 		if (sprframe->lump[0] == sprframe->lump[1])
357 		{
358 			ang = AngleMod(ang - thing->Angles.yaw + 180.0 + 45.0 / 2.0);
359 		}
360 		else
361 		{
362 			ang = AngleMod(ang - thing->Angles.yaw + 180.0 + 45.0 / 4.0);
363 		}
364 		vuint32 rot = (vuint32)(ang * 16 / 360.0) & 15;
365 		lump = sprframe->lump[rot];
366 		flip = sprframe->flip[rot];
367 	}
368 	else
369 	{
370 		// use single rotation for all views
371 		lump = sprframe->lump[0];
372 		flip = sprframe->flip[0];
373 	}
374 	if (lump <= 0)
375 	{
376 #ifdef PARANOID
377 		GCon->Logf(NAME_Dev, "Sprite frame %d : %d, not present",
378 			SpriteIndex, DispState->Frame);
379 #endif
380 		// Sprite lump is not present
381 		return;
382 	}
383 	VTexture* Tex = GTextureManager[lump];
384 	int TexWidth = Tex->GetWidth();
385 	int TexHeight = Tex->GetHeight();
386 	int TexSOffset = Tex->SOffset;
387 	int TexTOffset = Tex->TOffset;
388 
389 	TVec	sv[4];
390 
391 	TVec start = -TexSOffset * sprright * thing->ScaleX;
392 	TVec end = (TexWidth - TexSOffset) * sprright * thing->ScaleX;
393 
394 	if (r_fix_sprite_offsets && TexTOffset < TexHeight &&
395 		2 * TexTOffset + r_sprite_fix_delta >= TexHeight)
396 	{
397 		TexTOffset = TexHeight;
398 	}
399 	TVec topdelta = TexTOffset * sprup * thing->ScaleY;
400 	TVec botdelta = (TexTOffset - TexHeight) * sprup * thing->ScaleY;
401 
402 	sv[0] = sprorigin + start + botdelta;
403 	sv[1] = sprorigin + start + topdelta;
404 	sv[2] = sprorigin + end + topdelta;
405 	sv[3] = sprorigin + end + botdelta;
406 
407 	if (Alpha < 1.0 || Additive || r_sort_sprites)
408 	{
409 		DrawTranslucentPoly(NULL, sv, 4, lump, Alpha, Additive,
410 			thing->Translation, true, light, Fade, -sprforward, DotProduct(
411 			sprorigin, -sprforward), (flip ? -sprright : sprright) /
412 			thing->ScaleX, -sprup / thing->ScaleY, flip ? sv[2] : sv[1]);
413 	}
414 	else
415 	{
416 		Drawer->DrawSpritePolygon(sv, GTextureManager[lump], Alpha,
417 			Additive, GetTranslation(thing->Translation), ColourMap, light,
418 			Fade, -sprforward, DotProduct(sprorigin, -sprforward),
419 			(flip ? -sprright : sprright) / thing->ScaleX,
420 			-sprup / thing->ScaleY, flip ? sv[2] : sv[1]);
421 	}
422 	unguard;
423 }
424 
425 //==========================================================================
426 //
427 //	VRenderLevelShared::RenderTranslucentAliasModel
428 //
429 //==========================================================================
430 
RenderTranslucentAliasModel(VEntity * mobj,vuint32 light,vuint32 Fade,float Alpha,bool Additive,float TimeFrac)431 void VRenderLevelShared::RenderTranslucentAliasModel(VEntity* mobj,
432 	vuint32 light, vuint32 Fade, float Alpha, bool Additive, float TimeFrac)
433 {
434 	guard(VRenderLevelShared::RenderTranslucentAliasModel);
435 	int i;
436 
437 	float dist = fabs(DotProduct(mobj->Origin - vieworg, viewforward));
438 	int found = -1;
439 	float best_dist = -1;
440 	for (i = 0; i < MAX_TRANS_SPRITES; i++)
441 	{
442 		trans_sprite_t &spr = trans_sprites[i];
443 		if (!spr.Alpha)
444 		{
445 			spr.Ent = mobj;
446 			spr.light = light;
447 			spr.Fade = Fade;
448 			spr.Alpha = Alpha;
449 			spr.Additive = Additive;
450 			spr.dist = dist;
451 			spr.type = 2;
452 			spr.TimeFrac = TimeFrac;
453 			return;
454 		}
455 		if (spr.dist > best_dist)
456 		{
457 			found = i;
458 			best_dist = spr.dist;
459 		}
460 	}
461 	if (best_dist > dist)
462 	{
463 		//	All slots are full, draw and replace a far away sprite
464 		trans_sprite_t &spr = trans_sprites[found];
465 		if (spr.type == 2)
466 		{
467 			DrawEntityModel(spr.Ent, spr.light, spr.Fade, spr.Alpha,
468 				spr.Additive, spr.TimeFrac, RPASS_Normal);
469 		}
470 		else if (spr.type)
471 		{
472 			Drawer->DrawSpritePolygon(spr.Verts, GTextureManager[spr.lump],
473 				spr.Alpha, spr.Additive, GetTranslation(spr.translation),
474 				ColourMap, spr.light, spr.Fade, spr.normal, spr.pdist,
475 				spr.saxis, spr.taxis, spr.texorg);
476 		}
477 		else
478 		{
479 			check(spr.surf);
480 			Drawer->DrawMaskedPolygon(spr.surf, spr.Alpha, spr.Additive);
481 		}
482 		spr.Ent = mobj;
483 		spr.light = light;
484 		spr.Fade = Fade;
485 		spr.Alpha = Alpha;
486 		spr.Additive = Additive;
487 		spr.dist = dist;
488 		spr.type = 2;
489 		spr.TimeFrac = TimeFrac;
490 		return;
491 	}
492 	DrawEntityModel(mobj, light, Fade, Alpha, Additive, TimeFrac, RPASS_Normal);
493 	unguard;
494 }
495 
496 //==========================================================================
497 //
498 //	VRenderLevelShared::RenderAliasModel
499 //
500 //==========================================================================
501 
RenderAliasModel(VEntity * mobj,vuint32 light,vuint32 Fade,float Alpha,bool Additive,ERenderPass Pass)502 bool VRenderLevelShared::RenderAliasModel(VEntity* mobj, vuint32 light,
503 	vuint32 Fade, float Alpha, bool Additive, ERenderPass Pass)
504 {
505 	guard(VRenderLevelShared::RenderAliasModel);
506 	if (!r_models)
507 	{
508 		return false;
509 	}
510 
511 	float TimeFrac = 0;
512 	if (mobj->State->Time > 0)
513 	{
514 		TimeFrac = 1.0 - (mobj->StateTime / mobj->State->Time);
515 		TimeFrac = MID(0.0, TimeFrac, 1.0);
516 	}
517 
518 	//	Draw it
519 	if (Alpha < 1.0 || Additive)
520 	{
521 		if (!CheckAliasModelFrame(mobj, TimeFrac))
522 		{
523 			return false;
524 		}
525 		RenderTranslucentAliasModel(mobj, light, Fade, Alpha, Additive,
526 			TimeFrac);
527 		return true;
528 	}
529 	else
530 	{
531 		return DrawEntityModel(mobj, light, Fade, 1.0, false, TimeFrac,
532 			Pass);
533 	}
534 	unguard;
535 }
536 
537 //==========================================================================
538 //
539 //	VRenderLevelShared::RenderThing
540 //
541 //==========================================================================
542 
RenderThing(VEntity * mobj,ERenderPass Pass)543 void VRenderLevelShared::RenderThing(VEntity* mobj, ERenderPass Pass)
544 {
545 	guard(VRenderLevelShared::RenderThing);
546 	if (mobj == ViewEnt && (!r_chasecam || ViewEnt != cl->MO))
547 	{
548 		//	Don't draw camera actor.
549 		return;
550 	}
551 
552 	if ((mobj->EntityFlags & VEntity::EF_NoSector) ||
553 		(mobj->EntityFlags & VEntity::EF_Invisible))
554 	{
555 		return;
556 	}
557 	if (!mobj->State)
558 	{
559 		return;
560 	}
561 
562 	//	Skip things in subsectors that are not visible.
563 	int SubIdx = mobj->SubSector - Level->Subsectors;
564 	if (!(BspVis[SubIdx >> 3] & (1 << (SubIdx & 7))))
565 	{
566 		return;
567 	}
568 
569 	int RendStyle = mobj->RenderStyle;
570 	float Alpha = mobj->Alpha;
571 	bool Additive = false;
572 
573 	if (RendStyle == STYLE_SoulTrans)
574 	{
575 		RendStyle = STYLE_Translucent;
576 		Alpha = transsouls;
577 	}
578 	else if (RendStyle == STYLE_OptFuzzy)
579 	{
580 		RendStyle = r_drawfuzz ? STYLE_Fuzzy : STYLE_Translucent;
581 	}
582 
583 	switch (RendStyle)
584 	{
585 	case STYLE_None:
586 		return;
587 
588 	case STYLE_Normal:
589 		Alpha = 1.0;
590 		break;
591 
592 	case STYLE_Fuzzy:
593 		Alpha = 0.1;
594 		break;
595 
596 	case STYLE_Add:
597 		Additive = true;
598 		break;
599 	}
600 	Alpha = MID(0.0, Alpha, 1.0);
601 
602 	if (!Alpha)
603 	{
604 		// Never make a vissprite when MF2_DONTDRAW is flagged.
605 		return;
606 	}
607 
608 	//	Setup lighting
609 	vuint32 light;
610 	if (RendStyle == STYLE_Fuzzy)
611 	{
612 		light = 0;
613 	}
614 	else if ((mobj->State->Frame & VState::FF_FULLBRIGHT) ||
615 		(mobj->EntityFlags & (VEntity::EF_FullBright | VEntity::EF_Bright)))
616 	{
617 		light = 0xffffffff;
618 	}
619 	else
620 	{
621 		light = LightPoint(mobj->Origin);
622 	}
623 	vuint32 Fade = GetFade(SV_PointInRegion(mobj->Sector, mobj->Origin));
624 
625 	//	Try to draw a model. If it's a script and it doesn't
626 	// specify model for this frame, draw sprite instead.
627 	if (!RenderAliasModel(mobj, light, Fade, Alpha, Additive, Pass))
628 	{
629 		RenderSprite(mobj, light, Fade, Alpha, Additive);
630 	}
631 	unguard;
632 }
633 
634 //==========================================================================
635 //
636 //	VRenderLevelShared::RenderMobjs
637 //
638 //==========================================================================
639 
RenderMobjs(ERenderPass Pass)640 void VRenderLevelShared::RenderMobjs(ERenderPass Pass)
641 {
642 	guard(VRenderLevelShared::RenderMobjs);
643 	if (!r_draw_mobjs)
644 	{
645 		return;
646 	}
647 
648 	for (TThinkerIterator<VEntity> Ent(Level); Ent; ++Ent)
649 	{
650 		RenderThing(*Ent, Pass);
651 	}
652 	unguard;
653 }
654 
655 //==========================================================================
656 //
657 //	VRenderLevelShared::DrawTranslucentPolys
658 //
659 //==========================================================================
660 
DrawTranslucentPolys()661 void VRenderLevelShared::DrawTranslucentPolys()
662 {
663 	guard(VRenderLevelShared::DrawTranslucentPolys);
664 	int i, found;
665 	do
666 	{
667 		found = -1;
668 		float best_dist = -1;
669 		for (i = 0; i < MAX_TRANS_SPRITES; i++)
670 		{
671 			trans_sprite_t &spr = trans_sprites[i];
672 			if (!spr.Alpha)
673 			{
674 				continue;
675 			}
676 			if (spr.dist > best_dist)
677 			{
678 				found = i;
679 				best_dist = spr.dist;
680 			}
681 		}
682 		if (found != -1)
683 		{
684 			trans_sprite_t &spr = trans_sprites[found];
685 			if (spr.type == 2)
686 			{
687 				DrawEntityModel(spr.Ent, spr.light, spr.Fade, spr.Alpha,
688 					spr.Additive, spr.TimeFrac, RPASS_Normal);
689 			}
690 			else if (spr.type)
691 			{
692 				Drawer->DrawSpritePolygon(spr.Verts, GTextureManager[spr.lump],
693 					spr.Alpha, spr.Additive, GetTranslation(spr.translation),
694 					ColourMap, spr.light, spr.Fade, spr.normal, spr.pdist,
695 					spr.saxis, spr.taxis, spr.texorg);
696 			}
697 			else
698 			{
699 				check(spr.surf);
700 				Drawer->DrawMaskedPolygon(spr.surf, spr.Alpha, spr.Additive);
701 			}
702 			spr.Alpha = 0;
703 		}
704 	} while (found != -1);
705 	unguard;
706 }
707 
708 //==========================================================================
709 //
710 //	VRenderLevelShared::RenderPSprite
711 //
712 //==========================================================================
713 
RenderPSprite(VViewState * VSt,float PSP_DIST,vuint32 light,vuint32 Fade,float Alpha,bool Additive)714 void VRenderLevelShared::RenderPSprite(VViewState* VSt, float PSP_DIST,
715 	vuint32 light, vuint32 Fade, float Alpha, bool Additive)
716 {
717 	guard(VRenderLevelShared::RenderPSprite);
718 	spritedef_t*		sprdef;
719 	spriteframe_t*		sprframe;
720 	int					lump;
721 	bool				flip;
722 
723 	// decide which patch to use
724 	if ((vuint32)VSt->State->SpriteIndex >= MAX_SPRITE_MODELS)
725 	{
726 #ifdef PARANOID
727 		GCon->Logf("R_ProjectSprite: invalid sprite number %d",
728 			VSt->State->SpriteIndex);
729 #endif
730 		return;
731 	}
732 	sprdef = &sprites[VSt->State->SpriteIndex];
733 	if ((VSt->State->Frame & VState::FF_FRAMEMASK) >= sprdef->numframes)
734 	{
735 #ifdef PARANOID
736 		GCon->Logf("R_ProjectSprite: invalid sprite frame %d : %d",
737 			VSt->State->SpriteIndex, VSt->State->Frame);
738 #endif
739 		return;
740 	}
741 	sprframe = &sprdef->spriteframes[VSt->State->Frame & VState::FF_FRAMEMASK];
742 
743 	lump = sprframe->lump[0];
744 	flip = sprframe->flip[0];
745 	VTexture* Tex = GTextureManager[lump];
746 
747 	int TexWidth = Tex->GetWidth();
748 	int TexHeight = Tex->GetHeight();
749 	int TexSOffset = Tex->SOffset;
750 	int TexTOffset = Tex->TOffset;
751 
752 	TVec	dv[4];
753 
754 	float PSP_DISTI = 1.0 / PSP_DIST;
755 	TVec sprorigin = vieworg + PSP_DIST * viewforward;
756 
757 	float sprx = 160.0 - VSt->SX + TexSOffset;
758 	float spry = 100.0 - VSt->SY + TexTOffset;
759 
760 	spry -= cl->PSpriteSY;
761 
762 	//	1 / 160 = 0.00625
763 	TVec start = sprorigin - (sprx * PSP_DIST * 0.00625) * viewright;
764 	TVec end = start + (TexWidth * PSP_DIST * 0.00625) * viewright;
765 
766 	//	1 / 160.0 * 120 / 100 =	0.0075
767 	TVec topdelta = (spry * PSP_DIST * 0.0075) * viewup;
768 	TVec botdelta = topdelta - (TexHeight * PSP_DIST * 0.0075) * viewup;
769 	if (aspect_ratio > 1)
770 	{
771 		topdelta *= 100.0 / 120.0;
772 		botdelta *= 100.0 / 120.0;
773 	}
774 
775 	dv[0] = start + botdelta;
776 	dv[1] = start + topdelta;
777 	dv[2] = end + topdelta;
778 	dv[3] = end + botdelta;
779 
780 	TVec saxis;
781 	TVec taxis;
782 	TVec texorg;
783 	if (flip)
784 	{
785 		saxis = -(viewright * 160 * PSP_DISTI);
786 		texorg = dv[2];
787 	}
788 	else
789 	{
790 		saxis = viewright * 160 * PSP_DISTI;
791 		texorg = dv[1];
792 	}
793 	if (aspect_ratio == 0)
794 	{
795 		taxis = -(viewup * 160 * PSP_DISTI);
796 	}
797 	else if (aspect_ratio == 1)
798 	{
799 		taxis = -(viewup * 100 * 4 / 3 * PSP_DISTI);
800 	}
801 	else if (aspect_ratio == 2)
802 	{
803 		taxis = -(viewup * 100 * 16 / 9 * PSP_DISTI);
804 	}
805 	else if (aspect_ratio > 2)
806 	{
807 		taxis = -(viewup * 100 * 16 / 10 * PSP_DISTI);
808 	}
809 
810 	Drawer->DrawSpritePolygon(dv, GTextureManager[lump], Alpha, Additive,
811 		0, ColourMap, light, Fade, -viewforward,
812 		DotProduct(dv[0], -viewforward), saxis, taxis, texorg);
813 	unguard;
814 }
815 
816 //==========================================================================
817 //
818 //	VRenderLevelShared::RenderViewModel
819 //
820 //==========================================================================
821 
RenderViewModel(VViewState * VSt,vuint32 light,vuint32 Fade,float Alpha,bool Additive)822 bool VRenderLevelShared::RenderViewModel(VViewState* VSt, vuint32 light,
823 	vuint32 Fade, float Alpha, bool Additive)
824 {
825 	guard(VRenderLevelShared::RenderViewModel);
826 	if (!r_view_models)
827 	{
828 		return false;
829 	}
830 
831 	TVec origin = vieworg + (VSt->SX - 1.0) * viewright / 8.0 -
832 		(VSt->SY - 32.0) * viewup / 6.0;
833 
834 	float TimeFrac = 0;
835 	if (VSt->State->Time > 0)
836 	{
837 		TimeFrac = 1.0 - (VSt->StateTime / VSt->State->Time);
838 		TimeFrac = MID(0.0, TimeFrac, 1.0);
839 	}
840 
841 	bool Interpolate;
842 	// Check if we want to interpolate model frames
843 	if (!r_interpolate_frames)
844 	{
845 		Interpolate = false;
846 	}
847 	else
848 	{
849 		Interpolate = true;
850 	}
851 	return DrawAliasModel(origin, cl->ViewAngles, 1.0, 1.0, VSt->State,
852 		VSt->State->NextState ? VSt->State->NextState : VSt->State, NULL,
853 		0, light, Fade, Alpha, Additive, true, TimeFrac, Interpolate,
854 		RPASS_Normal);
855 	unguard;
856 }
857 
858 //==========================================================================
859 //
860 //	VRenderLevelShared::DrawPlayerSprites
861 //
862 //==========================================================================
863 
DrawPlayerSprites()864 void VRenderLevelShared::DrawPlayerSprites()
865 {
866 	guard(VRenderLevelShared::DrawPlayerSprites);
867 	if (!r_draw_psprites || r_chasecam)
868 	{
869 		return;
870 	}
871 
872 	int RendStyle = STYLE_Normal;
873 	float Alpha = 1.0;
874 	bool Additive = false;
875 
876 	cl->MO->eventGetViewEntRenderParams(Alpha, RendStyle);
877 
878 	if (RendStyle == STYLE_SoulTrans)
879 	{
880 		RendStyle = STYLE_Translucent;
881 		Alpha = transsouls;
882 	}
883 	else if (RendStyle == STYLE_OptFuzzy)
884 	{
885 		RendStyle = r_drawfuzz ? STYLE_Fuzzy : STYLE_Translucent;
886 	}
887 
888 	switch (RendStyle)
889 	{
890 	case STYLE_None:
891 		return;
892 
893 	case STYLE_Normal:
894 		Alpha = 1.0;
895 		break;
896 
897 	case STYLE_Fuzzy:
898 		Alpha = 0.1;
899 		break;
900 
901 	case STYLE_Add:
902 		Additive = true;
903 		break;
904 	}
905 	Alpha = MID(0.0, Alpha, 1.0);
906 
907 	// add all active psprites
908 	for (int i = 0; i < NUMPSPRITES; i++)
909 	{
910 		if (!cl->ViewStates[i].State)
911 		{
912 			continue;
913 		}
914 
915 		vuint32 light;
916 		if (RendStyle == STYLE_Fuzzy)
917 		{
918 			light = 0;
919 		}
920 		else if (cl->ViewStates[i].State->Frame & VState::FF_FULLBRIGHT)
921 		{
922 			light = 0xffffffff;
923 		}
924 		else
925 		{
926 			light = LightPoint(vieworg);
927 		}
928 		vuint32 Fade = GetFade(SV_PointInRegion(r_viewleaf->sector, cl->ViewOrg));
929 
930 		if (!RenderViewModel(&cl->ViewStates[i], light, Fade, Alpha,
931 			Additive))
932 		{
933 			RenderPSprite(&cl->ViewStates[i], 3 - i, light, Fade, Alpha,
934 				Additive);
935 		}
936 	}
937 	unguard;
938 }
939 
940 //==========================================================================
941 //
942 //	VRenderLevelShared::DrawCroshair
943 //
944 //==========================================================================
945 
DrawCroshair()946 void VRenderLevelShared::DrawCroshair()
947 {
948 	guard(VRenderLevelShared::DrawCroshair);
949 	if (croshair)
950 	{
951 		if (croshair_alpha < 0.0)	croshair_alpha = 0.0;
952 		if (croshair_alpha > 1.0)	croshair_alpha = 1.0;
953 
954 		int			cy;
955 		if (screenblocks < 11)
956 			cy = (480 - sb_height) / 2;
957 		else
958 			cy = 240;
959 		int handle = GTextureManager.AddPatch(VName(va("CROSHAI%i",
960 			(int)croshair), VName::AddLower8), TEXTYPE_Pic);
961 		R_DrawPic(320, cy, handle, croshair_alpha);
962 	}
963 	unguard;
964 }
965 
966 //==========================================================================
967 //
968 //  R_DrawSpritePatch
969 //
970 //==========================================================================
971 
R_DrawSpritePatch(int x,int y,int sprite,int frame,int rot,int TranslStart,int TranslEnd,int Colour)972 void R_DrawSpritePatch(int x, int y, int sprite, int frame, int rot,
973 	int TranslStart, int TranslEnd, int Colour)
974 {
975 	guard(R_DrawSpritePatch);
976 	bool			flip;
977 	int				lump;
978 
979 	spriteframe_t *sprframe = &sprites[sprite].spriteframes[frame & VState::FF_FRAMEMASK];
980 	flip = sprframe->flip[rot];
981 	lump = sprframe->lump[rot];
982 	VTexture* Tex = GTextureManager[lump];
983 
984 	Tex->GetWidth();
985 
986 	float x1 = x - Tex->SOffset;
987 	float y1 = y - Tex->TOffset;
988 	float x2 = x1 + Tex->GetWidth();
989 	float y2 = y1 + Tex->GetHeight();
990 
991 	x1 *= fScaleX;
992 	y1 *= fScaleY;
993 	x2 *= fScaleX;
994 	y2 *= fScaleY;
995 
996 	Drawer->DrawSpriteLump(x1, y1, x2, y2, Tex, R_GetCachedTranslation(
997 		R_SetMenuPlayerTrans(TranslStart, TranslEnd, Colour), NULL), flip);
998 	unguard;
999 }
1000