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