1 //**************************************************************************
2 //**
3 //**	##   ##    ##    ##   ##   ####     ####   ###     ###
4 //**	##   ##  ##  ##  ##   ##  ##  ##   ##  ##  ####   ####
5 //**	 ## ##  ##    ##  ## ##  ##    ## ##    ## ## ## ## ##
6 //**	 ## ##  ########  ## ##  ##    ## ##    ## ##  ###  ##
7 //**	  ###   ##    ##   ###    ##  ##   ##  ##  ##       ##
8 //**	   #    ##    ##    #      ####     ####   ##       ##
9 //**
10 //**	$Id: r_model.cpp 4342 2010-12-16 20:24:23Z dj_jl $
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 // HEADER FILES ------------------------------------------------------------
27 
28 #include "gamedefs.h"
29 #include "r_local.h"
30 
31 // MACROS ------------------------------------------------------------------
32 
33 #define SMOOTHSTEP(x) ((x) * (x) * (3.0 - 2.0 * (x)))
34 
35 enum { NUMVERTEXNORMALS = 162 };
36 
37 // TYPES -------------------------------------------------------------------
38 
39 struct VScriptSubModel
40 {
41 	struct VFrame
42 	{
43 		int		Index;
44 		int		PositionIndex;
45 		float	AlphaStart;
46 		float	AlphaEnd;
47 		TVec	Offset;
48 		TVec	Scale;
49 		int		SkinIndex;
50 	};
51 
52 	VMeshModel*			Model;
53 	VMeshModel*			PositionModel;
54 	int					SkinAnimSpeed;
55 	int					SkinAnimRange;
56 	int					Version;
57 	TArray<VFrame>		Frames;
58 	TArray<VName>		Skins;
59 	bool				FullBright;
60 	bool				NoShadow;
61 };
62 
63 struct VScriptModel
64 {
65 	VName						Name;
66 	TArray<VScriptSubModel>		SubModels;
67 };
68 
69 struct VScriptedModelFrame
70 {
71 	int			Number;
72 	float		Inter;
73 	int			ModelIndex;
74 	int			FrameIndex;
75 	float		AngleStart;
76 	float		AngleEnd;
77 	float		AlphaStart;
78 	float		AlphaEnd;
79 };
80 
81 struct VClassModelScript
82 {
83 	VName						Name;
84 	VModel*						Model;
85 	TArray<VScriptedModelFrame>	Frames;
86 };
87 
88 struct VModel
89 {
90 	VStr						Name;
91 	TArray<VScriptModel>		Models;
92 	VClassModelScript*			DefaultClass;
93 };
94 
95 struct TVertMap
96 {
97 	int		VertIndex;
98 	int		STIndex;
99 };
100 
101 struct VTempEdge
102 {
103 	vuint16				Vert1;
104 	vuint16				Vert2;
105 	vuint16				OrigVert1;
106 	vuint16				OrigVert2;
107 	vint16				Tri1;
108 	vint16				Tri2;
109 };
110 
111 // EXTERNAL FUNCTION PROTOTYPES --------------------------------------------
112 
113 // PUBLIC FUNCTION PROTOTYPES ----------------------------------------------
114 
115 // PRIVATE FUNCTION PROTOTYPES ---------------------------------------------
116 
117 // EXTERNAL DATA DECLARATIONS ----------------------------------------------
118 
119 // PUBLIC DATA DEFINITIONS -------------------------------------------------
120 
121 // precalculated dot products for quantized angles
122 float					r_avertexnormal_dots[SHADEDOT_QUANT][256] =
123 #include "anorm_dots.h"
124 ;
125 
126 // PRIVATE DATA DEFINITIONS ------------------------------------------------
127 
128 static TArray<VModel*>				mod_known;
129 static TArray<VMeshModel*>			GMeshModels;
130 static TArray<VClassModelScript*>	ClassModels;
131 
132 static float			r_avertexnormals[NUMVERTEXNORMALS][3] =
133 {
134 #include "anorms.h"
135 };
136 
137 // CODE --------------------------------------------------------------------
138 
139 //==========================================================================
140 //
141 //	R_InitModels
142 //
143 //==========================================================================
144 
R_InitModels()145 void R_InitModels()
146 {
147 	guard(R_InitModels);
148 	for (int Lump = W_IterateFile(-1, "models/models.xml"); Lump != -1;
149 		Lump = W_IterateFile(Lump, "models/models.xml"))
150 	{
151 		VStream* Strm = W_CreateLumpReaderNum(Lump);
152 		check(Strm);
153 
154 		//	Parse the file.
155 		VXmlDocument* Doc = new VXmlDocument();
156 		Doc->Parse(*Strm, "models/models.xml");
157 		delete Strm;
158 		Strm = NULL;
159 
160 		for (VXmlNode* N = Doc->Root.FindChild("include"); N; N = N->FindNext())
161 		{
162 			Mod_FindName(N->GetAttribute("file"));
163 		}
164 
165 		delete Doc;
166 		Doc = NULL;
167 	}
168 	unguard;
169 }
170 
171 //==========================================================================
172 //
173 //	R_FreeModels
174 //
175 //==========================================================================
176 
R_FreeModels()177 void R_FreeModels()
178 {
179 	guard(R_FreeModels);
180 	for (int i = 0; i < mod_known.Num(); i++)
181 	{
182 		delete mod_known[i];
183 		mod_known[i] = NULL;
184 	}
185 	mod_known.Clear();
186 
187 	for (int i = 0; i < GMeshModels.Num(); i++)
188 	{
189 		if (GMeshModels[i]->Data)
190 		{
191 			Z_Free(GMeshModels[i]->Data);
192 		}
193 		delete GMeshModels[i];
194 		GMeshModels[i] = NULL;
195 	}
196 	GMeshModels.Clear();
197 
198 	for (int i = 0; i < ClassModels.Num(); i++)
199 	{
200 		delete ClassModels[i];
201 		ClassModels[i] = NULL;
202 	}
203 	ClassModels.Clear();
204 	unguard;
205 }
206 
207 //==========================================================================
208 //
209 //	Mod_FindMeshModel
210 //
211 //==========================================================================
212 
Mod_FindMeshModel(const VStr & name)213 static VMeshModel* Mod_FindMeshModel(const VStr& name)
214 {
215 	guard(Mod_FindMeshModel);
216 	if (name.IsEmpty())
217 	{
218 		Sys_Error("Mod_ForName: NULL name");
219 	}
220 
221 	//
222 	// search the currently loaded models
223 	//
224 	for (int i = 0; i < GMeshModels.Num(); i++)
225 	{
226 		if (GMeshModels[i]->Name == name)
227 		{
228 			return GMeshModels[i];
229 		}
230 	}
231 
232 	VMeshModel* mod = new VMeshModel();
233 	mod->Name = name;
234 	mod->Data = NULL;
235 	GMeshModels.Append(mod);
236 
237 	return mod;
238 	unguard;
239 }
240 
241 //==========================================================================
242 //
243 //	ParseModelScript
244 //
245 //==========================================================================
246 
ParseModelScript(VModel * Mdl,VStream & Strm)247 static void ParseModelScript(VModel* Mdl, VStream& Strm)
248 {
249 	guard(ParseModelScript);
250 	//	Parse XML file.
251 	VXmlDocument* Doc = new VXmlDocument();
252 	Doc->Parse(Strm, Mdl->Name);
253 
254 	//	Verify that it's a model definition file.
255 	if (Doc->Root.Name != "vavoom_model_definition")
256 	{
257 		Sys_Error("%s is not a valid model definition file", *Mdl->Name);
258 	}
259 
260 	Mdl->DefaultClass = NULL;
261 
262 	//	Process model definitions.
263 	for (VXmlNode* N = Doc->Root.FindChild("model"); N; N = N->FindNext())
264 	{
265 		VScriptModel& SMdl = Mdl->Models.Alloc();
266 		SMdl.Name = *N->GetAttribute("name");
267 
268 		//	Process model parts.
269 		for (VXmlNode* SN = N->FindChild("md2"); SN; SN = SN->FindNext())
270 		{
271 			VScriptSubModel& Md2 = SMdl.SubModels.Alloc();
272 			Md2.Model = Mod_FindMeshModel(SN->GetAttribute("file").ToLower().FixFileSlashes());
273 
274 			//	Version
275 			Md2.Version = -1;
276 			if (SN->HasAttribute("version"))
277 			{
278 				Md2.Version = atoi(*SN->GetAttribute("version"));
279 			}
280 
281 			//	Position model
282 			Md2.PositionModel = NULL;
283 			if (SN->HasAttribute("position_file"))
284 			{
285 				Md2.PositionModel = Mod_FindMeshModel(SN->GetAttribute(
286 					"position_file").ToLower().FixFileSlashes());
287 			}
288 
289 			//	Skin animation
290 			Md2.SkinAnimSpeed = 0;
291 			Md2.SkinAnimRange = 0;
292 			if (SN->HasAttribute("skin_anim_speed"))
293 			{
294 				Md2.SkinAnimSpeed = atoi(*SN->GetAttribute("skin_anim_speed"));
295 				Md2.SkinAnimRange = atoi(*SN->GetAttribute("skin_anim_range"));
296 			}
297 
298 			//	Base offset
299 			TVec Offset(0.0, 0.0, 0.0);
300 			if (SN->HasAttribute("offset_x"))
301 			{
302 				Offset.x = atof(*SN->GetAttribute("offset_x"));
303 			}
304 			if (SN->HasAttribute("offset_y"))
305 			{
306 				Offset.y = atof(*SN->GetAttribute("offset_y"));
307 			}
308 			if (SN->HasAttribute("offset_z"))
309 			{
310 				Offset.z = atof(*SN->GetAttribute("offset_z"));
311 			}
312 
313 			//	Base scaling
314 			TVec Scale(1.0, 1.0, 1.0);
315 			if (SN->HasAttribute("scale"))
316 			{
317 				Scale.x = atof(*SN->GetAttribute("scale"));
318 				Scale.y = Scale.x;
319 				Scale.z = Scale.x;
320 			}
321 			if (SN->HasAttribute("scale_x"))
322 			{
323 				Scale.x = atof(*SN->GetAttribute("scale_x"));
324 			}
325 			if (SN->HasAttribute("scale_y"))
326 			{
327 				Scale.y = atof(*SN->GetAttribute("scale_y"));
328 			}
329 			if (SN->HasAttribute("scale_z"))
330 			{
331 				Scale.z = atof(*SN->GetAttribute("scale_z"));
332 			}
333 
334 			//	Full-bright flag.
335 			Md2.FullBright = false;
336 			if (SN->HasAttribute("fullbright"))
337 			{
338 				Md2.FullBright = !SN->GetAttribute("fullbright").ICmp("true");
339 			}
340 
341 			//	No shadow flag.
342 			Md2.NoShadow = false;
343 			if (SN->HasAttribute("noshadow"))
344 			{
345 				Md2.NoShadow = !SN->GetAttribute("noshadow").ICmp("true");
346 			}
347 
348 			//	Process frames.
349 			for (VXmlNode* FN = SN->FindChild("frame"); FN; FN = FN->FindNext())
350 			{
351 				VScriptSubModel::VFrame& F = Md2.Frames.Alloc();
352 				F.Index = atoi(*FN->GetAttribute("index"));
353 
354 				//	Position model frame index
355 				F.PositionIndex = 0;
356 				if (FN->HasAttribute("position_index"))
357 				{
358 					F.PositionIndex = atoi(*FN->GetAttribute("position_index"));
359 				}
360 
361 				//	Offset
362 				F.Offset = Offset;
363 				if (FN->HasAttribute("offset_x"))
364 				{
365 					F.Offset.x = atof(*FN->GetAttribute("offset_x"));
366 				}
367 				if (FN->HasAttribute("offset_y"))
368 				{
369 					F.Offset.y = atof(*FN->GetAttribute("offset_y"));
370 				}
371 				if (FN->HasAttribute("offset_z"))
372 				{
373 					F.Offset.z = atof(*FN->GetAttribute("offset_z"));
374 				}
375 
376 				//	Scale
377 				F.Scale = Scale;
378 				if (FN->HasAttribute("scale"))
379 				{
380 					F.Scale.x = atof(*FN->GetAttribute("scale"));
381 					F.Scale.y = F.Scale.x;
382 					F.Scale.z = F.Scale.x;
383 				}
384 				if (FN->HasAttribute("scale_x"))
385 				{
386 					F.Scale.x = atof(*FN->GetAttribute("scale_x"));
387 				}
388 				if (FN->HasAttribute("scale_y"))
389 				{
390 					F.Scale.y = atof(*FN->GetAttribute("scale_y"));
391 				}
392 				if (FN->HasAttribute("scale_z"))
393 				{
394 					F.Scale.z = atof(*FN->GetAttribute("scale_z"));
395 				}
396 
397 				//	Alpha
398 				F.AlphaStart = 1.0;
399 				F.AlphaEnd = 1.0;
400 				if (FN->HasAttribute("alpha_start"))
401 				{
402 					F.AlphaStart = atof(*FN->GetAttribute("alpha_start"));
403 				}
404 				if (FN->HasAttribute("alpha_end"))
405 				{
406 					F.AlphaEnd = atof(*FN->GetAttribute("alpha_end"));
407 				}
408 
409 				//	Skin index
410 				F.SkinIndex = -1;
411 				if (FN->HasAttribute("skin_index"))
412 				{
413 					F.SkinIndex = atoi(*FN->GetAttribute("skin_index"));
414 				}
415 			}
416 
417 			//	Process skins.
418 			for (VXmlNode* SkN = SN->FindChild("skin"); SkN; SkN = SkN->FindNext())
419 			{
420 				Md2.Skins.Append(*SkN->GetAttribute("file").ToLower().FixFileSlashes());
421 			}
422 		}
423 	}
424 
425 	bool ClassDefined = false;
426 	for (VXmlNode* CN = Doc->Root.FindChild("class"); CN; CN = CN->FindNext())
427 	{
428 		VClassModelScript* Cls = new VClassModelScript();
429 		Cls->Model = Mdl;
430 		Cls->Name = *CN->GetAttribute("name");
431 		if (!Mdl->DefaultClass)
432 			Mdl->DefaultClass = Cls;
433 		ClassModels.Append(Cls);
434 		ClassDefined = true;
435 
436 		//	Process frames
437 		for (VXmlNode* N = CN->FindChild("state"); N; N = N->FindNext())
438 		{
439 			VScriptedModelFrame& F = Cls->Frames.Alloc();
440 			F.Number = atoi(*N->GetAttribute("index"));
441 			F.FrameIndex = atoi(*N->GetAttribute("frame_index"));
442 			F.ModelIndex = -1;
443 			VStr MdlName = N->GetAttribute("model");
444 			for (int i = 0; i < Mdl->Models.Num(); i++)
445 			{
446 				if (Mdl->Models[i].Name == *MdlName)
447 				{
448 					F.ModelIndex = i;
449 					break;
450 				}
451 			}
452 			if (F.ModelIndex == -1)
453 			{
454 				Sys_Error("%s has no model %s", *Mdl->Name, *MdlName);
455 			}
456 
457 			F.Inter = 0.0;
458 			if (N->HasAttribute("inter"))
459 			{
460 				F.Inter = atof(*N->GetAttribute("inter"));
461 			}
462 
463 			F.AngleStart = 0.0;
464 			F.AngleEnd = 0.0;
465 			if (N->HasAttribute("angle_start"))
466 			{
467 				F.AngleStart = atof(*N->GetAttribute("angle_start"));
468 			}
469 			if (N->HasAttribute("angle_end"))
470 			{
471 				F.AngleEnd = atof(*N->GetAttribute("angle_end"));
472 			}
473 
474 			F.AlphaStart = 1.0;
475 			F.AlphaEnd = 1.0;
476 			if (N->HasAttribute("alpha_start"))
477 			{
478 				F.AlphaStart = atof(*N->GetAttribute("alpha_start"));
479 			}
480 			if (N->HasAttribute("alpha_end"))
481 			{
482 				F.AlphaEnd = atof(*N->GetAttribute("alpha_end"));
483 			}
484 		}
485 		if (!Cls->Frames.Num())
486 		{
487 			Sys_Error("%s class %s has no states defined",
488 				*Mdl->Name, *Cls->Name);
489 		}
490 	}
491 	if (!ClassDefined)
492 	{
493 		Sys_Error("%s defined no classes", *Mdl->Name);
494 	}
495 
496 	//	We don't need the XML file anymore.
497 	delete Doc;
498 	Doc = NULL;
499 	unguard;
500 }
501 
502 //==========================================================================
503 //
504 //	Mod_FindName
505 //
506 //==========================================================================
507 
Mod_FindName(const VStr & name)508 VModel* Mod_FindName(const VStr& name)
509 {
510 	guard(Mod_FindName);
511 	if (name.IsEmpty())
512 	{
513 		Sys_Error("Mod_ForName: NULL name");
514 	}
515 
516 	//
517 	// search the currently loaded models
518 	//
519 	for (int i = 0; i < mod_known.Num(); i++)
520 	{
521 		if (mod_known[i]->Name == name)
522 		{
523 			return mod_known[i];
524 		}
525 	}
526 
527 	VModel* mod = new VModel();
528 	mod->Name = name;
529 	mod_known.Append(mod);
530 	//
531 	// load the file
532 	//
533 	VStream* Strm = FL_OpenFileRead(mod->Name);
534 	if (!Strm)
535 	{
536 		Sys_Error("Couldn't load %s", *mod->Name);
537 	}
538 	ParseModelScript(mod, *Strm);
539 	delete Strm;
540 	Strm = NULL;
541 	return mod;
542 	unguard;
543 }
544 
545 //==========================================================================
546 //
547 //	AddEdge
548 //
549 //==========================================================================
550 
AddEdge(TArray<VTempEdge> & Edges,int Vert1,int OrigVert1,int Vert2,int OrigVert2,int Tri)551 static void AddEdge(TArray<VTempEdge>& Edges, int Vert1, int OrigVert1,
552 	int Vert2, int OrigVert2, int Tri)
553 {
554 	guard(AddEdge);
555 	//	Check for a match. Compare original vertex indices since texture
556 	// coordinates are not important here.
557 	for (int i = 0; i < Edges.Num(); i++)
558 	{
559 		VTempEdge& E = Edges[i];
560 		if (E.Tri2 == -1 && E.OrigVert1 == OrigVert2 && E.OrigVert2 == OrigVert1)
561 		{
562 			E.Tri2 = Tri;
563 			return;
564 		}
565 	}
566 
567 	//	Add new edge
568 	VTempEdge& E = Edges.Alloc();
569 	E.Vert1 = Vert1;
570 	E.Vert2 = Vert2;
571 	E.OrigVert1 = OrigVert1;
572 	E.OrigVert2 = OrigVert2;
573 	E.Tri1 = Tri;
574 	E.Tri2 = -1;
575 	unguard;
576 }
577 
578 //==========================================================================
579 //
580 //	Mod_SwapAliasModel
581 //
582 //==========================================================================
583 
Mod_SwapAliasModel(VMeshModel * mod)584 static void Mod_SwapAliasModel(VMeshModel* mod)
585 {
586 	guard(Mod_SwapAliasModel);
587 	mmdl_t				*pmodel;
588 	mstvert_t			*pstverts;
589 	mtriangle_t			*ptri;
590 	mframe_t			*pframe;
591 	vint32				*pcmds;
592 
593 	pmodel = mod->Data;
594 	mod->Uploaded = false;
595 	mod->VertsBuffer = 0;
596 	mod->IndexBuffer = 0;
597 
598 	//
599 	// endian-adjust and swap the data, starting with the alias model header
600 	//
601 	for (int i = 0; i < (int)sizeof(mmdl_t) / 4; i++)
602 	{
603 		((vint32*)pmodel)[i] = LittleLong(((vint32*)pmodel)[i]);
604 	}
605 
606 	if (pmodel->version != ALIAS_VERSION)
607 		Sys_Error("%s has wrong version number (%i should be %i)",
608 			*mod->Name, pmodel->version, ALIAS_VERSION);
609 
610 	if (pmodel->numverts <= 0)
611 		Sys_Error("model %s has no vertices", *mod->Name);
612 
613 	if (pmodel->numverts > MAXALIASVERTS)
614 		Sys_Error("model %s has too many vertices", *mod->Name);
615 
616 	if (pmodel->numstverts <= 0)
617 		Sys_Error("model %s has no texture vertices", *mod->Name);
618 
619 	if (pmodel->numstverts > MAXALIASSTVERTS)
620 		Sys_Error("model %s has too many texture vertices", *mod->Name);
621 
622 	if (pmodel->numtris <= 0)
623 		Sys_Error("model %s has no triangles", *mod->Name);
624 
625 	if (pmodel->skinwidth & 0x03)
626 		Sys_Error("Mod_LoadAliasModel: skinwidth not multiple of 4");
627 
628 	if (pmodel->numskins < 1)
629 		Sys_Error("Mod_LoadAliasModel: Invalid # of skins: %d\n", pmodel->numskins);
630 
631 	if (pmodel->numframes < 1)
632 		Sys_Error("Mod_LoadAliasModel: Invalid # of frames: %d\n", pmodel->numframes);
633 
634 	//
635 	// base s and t vertices
636 	//
637 	pstverts = (mstvert_t*)((byte*)pmodel + pmodel->ofsstverts);
638 	for (int i = 0; i < pmodel->numstverts; i++)
639 	{
640 		pstverts[i].s = LittleShort(pstverts[i].s);
641 		pstverts[i].t = LittleShort(pstverts[i].t);
642 	}
643 
644 	//
645 	// triangles
646 	//
647 	TArray<TVertMap> VertMap;
648 	TArray<VTempEdge> Edges;
649 	mod->Tris.SetNum(pmodel->numtris);
650 	ptri = (mtriangle_t *)((byte*)pmodel + pmodel->ofstris);
651 	for (int i = 0; i < pmodel->numtris; i++)
652 	{
653 		for (int j = 0; j < 3; j++)
654 		{
655 			ptri[i].vertindex[j] = LittleShort(ptri[i].vertindex[j]);
656 			ptri[i].stvertindex[j] = LittleShort(ptri[i].stvertindex[j]);
657 
658 			bool Found = false;
659 			for (int vi = 0; vi < VertMap.Num(); vi++)
660 			{
661 				if (VertMap[vi].VertIndex == ptri[i].vertindex[j] &&
662 					VertMap[vi].STIndex == ptri[i].stvertindex[j])
663 				{
664 					Found = true;
665 					mod->Tris[i].VertIndex[j] = vi;
666 					break;
667 				}
668 			}
669 			if (!Found)
670 			{
671 				mod->Tris[i].VertIndex[j] = VertMap.Num();
672 				TVertMap& V = VertMap.Alloc();
673 				V.VertIndex = ptri[i].vertindex[j];
674 				V.STIndex = ptri[i].stvertindex[j];
675 			}
676 		}
677 		for (int j = 0; j < 3; j++)
678 		{
679 			AddEdge(Edges, mod->Tris[i].VertIndex[j], ptri[i].vertindex[j],
680 				mod->Tris[i].VertIndex[(j + 1) % 3], ptri[i].vertindex[(j + 1) % 3], i);
681 		}
682 	}
683 
684 	mod->Edges.SetNum(Edges.Num());
685 	for (int i = 0; i < Edges.Num(); i++)
686 	{
687 		mod->Edges[i].Vert1 = Edges[i].Vert1;
688 		mod->Edges[i].Vert2 = Edges[i].Vert2;
689 		mod->Edges[i].Tri1 = Edges[i].Tri1;
690 		mod->Edges[i].Tri2 = Edges[i].Tri2;
691 	}
692 
693 	//
694 	//	Calculate remapped ST verts.
695 	//
696 	mod->STVerts.SetNum(VertMap.Num());
697 	for (int i = 0; i < VertMap.Num(); i++)
698 	{
699 		mod->STVerts[i].S = (float)pstverts[VertMap[i].STIndex].s / (float)pmodel->skinwidth;
700 		mod->STVerts[i].T = (float)pstverts[VertMap[i].STIndex].t / (float)pmodel->skinheight;
701 	}
702 
703 	//
704 	// frames
705 	//
706 	mod->Frames.SetNum(pmodel->numframes);
707 	mod->AllVerts.SetNum(pmodel->numframes * VertMap.Num());
708 	mod->AllNormals.SetNum(pmodel->numframes * VertMap.Num());
709 	mod->AllPlanes.SetNum(pmodel->numframes * pmodel->numtris);
710 	pframe = (mframe_t *)((byte*)pmodel + pmodel->ofsframes);
711 	for (int i = 0; i < pmodel->numframes; i++)
712 	{
713 		pframe->scale[0] = LittleFloat(pframe->scale[0]);
714 		pframe->scale[1] = LittleFloat(pframe->scale[1]);
715 		pframe->scale[2] = LittleFloat(pframe->scale[2]);
716 		pframe->scale_origin[0] = LittleFloat(pframe->scale_origin[0]);
717 		pframe->scale_origin[1] = LittleFloat(pframe->scale_origin[1]);
718 		pframe->scale_origin[2] = LittleFloat(pframe->scale_origin[2]);
719 
720 		VMeshFrame& Frame = mod->Frames[i];
721 		Frame.Verts = &mod->AllVerts[i * VertMap.Num()];
722 		Frame.Normals = &mod->AllNormals[i * VertMap.Num()];
723 		Frame.Planes = &mod->AllPlanes[i * pmodel->numtris];
724 		Frame.VertsOffset = 0;
725 		Frame.NormalsOffset = 0;
726 		trivertx_t* Verts = (trivertx_t *)(pframe + 1);
727 		for (int j = 0; j < VertMap.Num(); j++)
728 		{
729 			trivertx_t& Vert = Verts[VertMap[j].VertIndex];
730 			Frame.Verts[j].x = Vert.v[0] * pframe->scale[0] + pframe->scale_origin[0];
731 			Frame.Verts[j].y = Vert.v[1] * pframe->scale[1] + pframe->scale_origin[1];
732 			Frame.Verts[j].z = Vert.v[2] * pframe->scale[2] + pframe->scale_origin[2];
733 			Frame.Normals[j] = r_avertexnormals[Vert.lightnormalindex];
734 		}
735 		for (int j = 0; j < pmodel->numtris; j++)
736 		{
737 			TVec v1 = Frame.Verts[mod->Tris[j].VertIndex[0]];
738 			TVec v2 = Frame.Verts[mod->Tris[j].VertIndex[1]];
739 			TVec v3 = Frame.Verts[mod->Tris[j].VertIndex[2]];
740 			TVec d1 = v2 - v3;
741 			TVec d2 = v1 - v3;
742 			TVec PlaneNormal = Normalise(CrossProduct(d1, d2));
743 			float PlaneDist = DotProduct(PlaneNormal, v3);
744 			Frame.Planes[j].Set(PlaneNormal, PlaneDist);
745 		}
746 		pframe = (mframe_t*)((byte*)pframe + pmodel->framesize);
747 	}
748 
749 	//
750 	// commands
751 	//
752 	pcmds = (vint32*)((byte*)pmodel + pmodel->ofscmds);
753 	for (int i = 0; i < pmodel->numcmds; i++)
754 	{
755 		pcmds[i] = LittleLong(pcmds[i]);
756 	}
757 
758 	//
759 	//	Skins
760 	//
761 	mskin_t* pskindesc = (mskin_t *)((byte *)pmodel + pmodel->ofsskins);
762 	for (int i = 0; i < pmodel->numskins; i++)
763 	{
764 		mod->Skins.Append(*VStr(pskindesc[i].name).ToLower());
765 	}
766 	unguard;
767 }
768 
769 //==========================================================================
770 //
771 //	Mod_Extradata
772 //
773 //	Loads the data if needed
774 //
775 //==========================================================================
776 
Mod_Extradata(VMeshModel * mod)777 static mmdl_t* Mod_Extradata(VMeshModel* mod)
778 {
779 	guard(Mod_Extradata);
780 	if (mod->Data)
781 	{
782 		return mod->Data;
783 	}
784 
785 	//
786 	// load the file
787 	//
788 	VStream* Strm = FL_OpenFileRead(mod->Name);
789 	if (!Strm)
790 	{
791 		Sys_Error("Couldn't load %s", *mod->Name);
792 	}
793 
794 	mod->Data = (mmdl_t*)Z_Malloc(Strm->TotalSize());
795 	Strm->Serialise(mod->Data, Strm->TotalSize());
796 	delete Strm;
797 	Strm = NULL;
798 
799 	if (LittleLong(*(vuint32*)mod->Data) != IDPOLY2HEADER)
800 	{
801 		Sys_Error("model %s is not a md2 model", *mod->Name);
802 	}
803 
804 	// swap model
805 	Mod_SwapAliasModel(mod);
806 
807 	return mod->Data;
808 	unguard;
809 }
810 
811 //==========================================================================
812 //
813 //	PositionModel
814 //
815 //==========================================================================
816 
PositionModel(TVec & Origin,TAVec & Angles,VMeshModel * wpmodel,int InFrame)817 static void PositionModel(TVec& Origin, TAVec& Angles, VMeshModel* wpmodel,
818 	int InFrame)
819 {
820 	guard(PositionModel);
821 	mmdl_t *pmdl = (mmdl_t*)Mod_Extradata(wpmodel);
822 	int frame = InFrame;
823 	if ((frame >= pmdl->numframes) || (frame < 0))
824 	{
825 		frame = 0;
826 	}
827 	mtriangle_t *ptris = (mtriangle_t*)((byte*)pmdl + pmdl->ofstris);
828 	mframe_t *pframe = (mframe_t*)((byte*)pmdl + pmdl->ofsframes +
829 		frame * pmdl->framesize);
830 	trivertx_t *pverts = (trivertx_t *)(pframe + 1);
831 	TVec p[3];
832 	for (int vi = 0; vi < 3; vi++)
833 	{
834 		p[vi].x = pverts[ptris[0].vertindex[vi]].v[0] * pframe->scale[0] + pframe->scale_origin[0];
835 		p[vi].y = pverts[ptris[0].vertindex[vi]].v[1] * pframe->scale[1] + pframe->scale_origin[1];
836 		p[vi].z = pverts[ptris[0].vertindex[vi]].v[2] * pframe->scale[2] + pframe->scale_origin[2];
837 	}
838 	TVec md_forward, md_left, md_up;
839 	AngleVectors(Angles, md_forward, md_left, md_up);
840 	md_left = -md_left;
841 	Origin += md_forward * p[0].x + md_left * p[0].y + md_up * p[0].z;
842 	TAVec wangles;
843 	VectorAngles(p[1] - p[0], wangles);
844 	Angles.yaw = AngleMod(Angles.yaw + wangles.yaw);
845 	Angles.pitch = AngleMod(Angles.pitch + wangles.pitch);
846 	unguard;
847 }
848 
849 //==========================================================================
850 //
851 //	FindFrame
852 //
853 //==========================================================================
854 
FindFrame(const VClassModelScript & Cls,int Frame,float Inter)855 static int FindFrame(const VClassModelScript& Cls, int Frame, float Inter)
856 {
857 	guard(FindFrame);
858 	int Ret = -1;
859 	for (int i = 0; i < Cls.Frames.Num(); i++)
860 	{
861 		if (Cls.Frames[i].Number == Frame && Cls.Frames[i].Inter <= Inter)
862 		{
863 			Ret = i;
864 		}
865 	}
866 	return Ret;
867 	unguard;
868 }
869 
870 //==========================================================================
871 //
872 //	FindNextFrame
873 //
874 //==========================================================================
875 
FindNextFrame(const VClassModelScript & Cls,int FIdx,int Frame,float Inter,float & InterpFrac)876 static int FindNextFrame(const VClassModelScript& Cls, int FIdx, int Frame,
877 	float Inter, float& InterpFrac)
878 {
879 	guard(FindNextFrame);
880 	const VScriptedModelFrame& FDef = Cls.Frames[FIdx];
881 	if (FIdx < Cls.Frames.Num() - 1 &&
882 		Cls.Frames[FIdx + 1].Number == FDef.Number)
883 	{
884 		InterpFrac = (Inter - FDef.Inter) / (Cls.Frames[FIdx + 1].Inter -
885 			FDef.Inter);
886 		return FIdx + 1;
887 	}
888 	InterpFrac = (Inter - FDef.Inter) / (1.0 - FDef.Inter);
889 	return FindFrame(Cls, Frame, 0);
890 	unguard;
891 }
892 
893 //==========================================================================
894 //
895 //	DrawModel
896 //
897 //==========================================================================
898 
DrawModel(VLevel * Level,const TVec & Org,const TAVec & Angles,float ScaleX,float ScaleY,VClassModelScript & Cls,int FIdx,int NFIdx,VTextureTranslation * Trans,int ColourMap,int Version,vuint32 Light,vuint32 Fade,float Alpha,bool Additive,bool IsViewModel,float Inter,bool Interpolate,const TVec & LightPos,float LightRadius,ERenderPass Pass)899 static void DrawModel(VLevel* Level, const TVec& Org, const TAVec& Angles,
900 	float ScaleX, float ScaleY, VClassModelScript& Cls, int FIdx, int NFIdx,
901 	VTextureTranslation* Trans, int ColourMap, int Version, vuint32 Light,
902 	vuint32 Fade, float Alpha, bool Additive, bool IsViewModel, float Inter,
903 	bool Interpolate, const TVec& LightPos, float LightRadius, ERenderPass Pass)
904 {
905 	guard(DrawModel);
906 	VScriptedModelFrame& FDef = Cls.Frames[FIdx];
907 	VScriptedModelFrame& NFDef = Cls.Frames[NFIdx];
908 	VScriptModel& ScMdl = Cls.Model->Models[FDef.ModelIndex];
909 	for (int i = 0; i < ScMdl.SubModels.Num(); i++)
910 	{
911 		VScriptSubModel& SubMdl = ScMdl.SubModels[i];
912 		if (SubMdl.Version != -1 && SubMdl.Version != Version)
913 		{
914 			continue;
915 		}
916 		if (FDef.FrameIndex >= SubMdl.Frames.Num())
917 		{
918 			GCon->Logf("Bad sub-model frame index %d", FDef.FrameIndex);
919 			continue;
920 		}
921 		if (Interpolate && NFDef.FrameIndex >= SubMdl.Frames.Num() &&
922 			NFDef.ModelIndex != FDef.ModelIndex)
923 		{
924 			NFDef.FrameIndex = FDef.FrameIndex;
925 			Interpolate = false;
926 			continue;
927 		}
928 		if (Interpolate && FDef.ModelIndex != NFDef.ModelIndex)
929 		{
930 			Interpolate = false;
931 		}
932 		if (NFDef.FrameIndex >= SubMdl.Frames.Num())
933 		{
934 			continue;
935 		}
936 		VScriptSubModel::VFrame& F = SubMdl.Frames[FDef.FrameIndex];
937 		VScriptSubModel::VFrame& NF = SubMdl.Frames[NFDef.FrameIndex];
938 
939 		//	Locate the proper data.
940 		mmdl_t* pmdl = (mmdl_t*)Mod_Extradata(SubMdl.Model);
941 
942 		//	Skin aniations.
943 		int Md2SkinIdx = 0;
944 		if (F.SkinIndex >= 0)
945 		{
946 			Md2SkinIdx = F.SkinIndex;
947 		}
948 		else if (SubMdl.SkinAnimSpeed)
949 		{
950 			Md2SkinIdx = int((Level ? Level->Time : 0) * SubMdl.SkinAnimSpeed) %
951 				SubMdl.SkinAnimRange;
952 		}
953 
954 		//	Get the proper skin texture ID.
955 		int SkinID;
956 		if (SubMdl.Skins.Num())
957 		{
958 			//	Skins defined in definition file override all skins in MD2 file.
959 			if (Md2SkinIdx < 0 || Md2SkinIdx >= SubMdl.Skins.Num())
960 			{
961 				SkinID = GTextureManager.AddFileTexture(
962 					SubMdl.Skins[0], TEXTYPE_Skin);
963 			}
964 			else
965 			{
966 				SkinID = GTextureManager.AddFileTexture(
967 					SubMdl.Skins[Md2SkinIdx], TEXTYPE_Skin);
968 			}
969 		}
970 		else
971 		{
972 			if (Md2SkinIdx < 0 || Md2SkinIdx >= pmdl->numskins)
973 			{
974 				SkinID = GTextureManager.AddFileTexture(
975 					SubMdl.Model->Skins[0], TEXTYPE_Skin);
976 			}
977 			else
978 			{
979 				SkinID = GTextureManager.AddFileTexture(
980 					SubMdl.Model->Skins[Md2SkinIdx], TEXTYPE_Skin);
981 			}
982 		}
983 
984 		//	Get and verify frame number.
985 		int Md2Frame = F.Index;
986 		if (Md2Frame >= pmdl->numframes || Md2Frame < 0)
987 		{
988 			GCon->Logf(NAME_Dev, "no such frame %d in %s", Md2Frame,
989 				*SubMdl.Model->Name);
990 			Md2Frame = 0;
991 			//	Stop further warnings.
992 			F.Index = 0;
993 		}
994 
995 		//  Get and verify next frame number.
996 		int Md2NextFrame = NF.Index;
997 		if (Md2NextFrame >= pmdl->numframes || Md2NextFrame < 0)
998 		{
999 			GCon->Logf(NAME_Dev, "no such next frame %d in %s", Md2NextFrame,
1000 				*SubMdl.Model->Name);
1001 			Md2NextFrame = 0;
1002 			//	Stop further warnings.
1003 			NF.Index = 0;
1004 		}
1005 
1006 		//	Position
1007 		TVec Md2Org = Org;
1008 
1009 		//	Angle
1010 		TAVec Md2Angle = Angles;
1011 		if (FDef.AngleStart || FDef.AngleEnd != 1.0)
1012 		{
1013 			Md2Angle.yaw = AngleMod(Md2Angle.yaw + FDef.AngleStart +
1014 				(FDef.AngleEnd - FDef.AngleStart) * Inter);
1015 		}
1016 
1017 		//	Position model
1018 		if (SubMdl.PositionModel)
1019 		{
1020 			PositionModel(Md2Org, Md2Angle, SubMdl.PositionModel, F.PositionIndex);
1021 		}
1022 
1023 		//	Alpha
1024 		float Md2Alpha = Alpha;
1025 		if (FDef.AlphaStart != 1.0 || FDef.AlphaEnd != 1.0)
1026 		{
1027 			Md2Alpha *= FDef.AlphaStart + (FDef.AlphaEnd - FDef.AlphaStart) * Inter;
1028 		}
1029 		if (F.AlphaStart != 1.0 || F.AlphaEnd != 1.0)
1030 		{
1031 			Md2Alpha *= F.AlphaStart + (F.AlphaEnd - F.AlphaStart) * Inter;
1032 		}
1033 		switch (Pass)
1034 		{
1035 		case RPASS_Normal:
1036 			break;
1037 
1038 		case RPASS_Ambient:
1039 		case RPASS_ShadowVolumes:
1040 		case RPASS_Light:
1041 		case RPASS_Textures:
1042 		case RPASS_Fog:
1043 			if (Md2Alpha < 1 || SubMdl.NoShadow)
1044 			{
1045 				continue;
1046 			}
1047 			break;
1048 
1049 		case RPASS_NonShadow:
1050 			if (Md2Alpha >= 1.0 && !Additive && !SubMdl.NoShadow)
1051 			{
1052 				continue;
1053 			}
1054 			break;
1055 		}
1056 
1057 		float smooth_inter = Interpolate ? SMOOTHSTEP(Inter) : 0.0;
1058 
1059 		//	Scale, in case of models thing's ScaleX scales x and y and ScaleY
1060 		// scales z.
1061 		TVec Scale;
1062 		if (Interpolate)
1063 		{
1064 			// Interpolate Scale
1065 			Scale.x = (F.Scale.x + smooth_inter * (NF.Scale.x - F.Scale.x) * ScaleX);
1066 			Scale.y = (F.Scale.y + smooth_inter * (NF.Scale.y - F.Scale.y) * ScaleX);
1067 			Scale.z = (F.Scale.z + smooth_inter * (NF.Scale.z - F.Scale.z) * ScaleY);
1068 		}
1069 		else
1070 		{
1071 			Scale.x = F.Scale.x * ScaleX;
1072 			Scale.y = F.Scale.y * ScaleX;
1073 			Scale.z = F.Scale.z * ScaleY;
1074 		}
1075 
1076 		TVec Offset;
1077 		if (Interpolate)
1078 		{
1079 			// Interpolate Offsets too
1080 			Offset.x = ((1 - smooth_inter) * F.Offset.x + (smooth_inter) * NF.Offset.x);
1081 			Offset.y = ((1 - smooth_inter) * F.Offset.y + (smooth_inter) * NF.Offset.y);
1082 			Offset.z = ((1 - smooth_inter) * F.Offset.z + (smooth_inter) * NF.Offset.z);
1083 		}
1084 		else
1085 		{
1086 			Offset.x = F.Offset.x;
1087 			Offset.y = F.Offset.y;
1088 			Offset.z = F.Offset.z;
1089 		}
1090 
1091 		//	Light
1092 		vuint32 Md2Light = Light;
1093 		if (SubMdl.FullBright)
1094 		{
1095 			Md2Light = 0xffffffff;
1096 		}
1097 
1098 		switch (Pass)
1099 		{
1100 		case RPASS_Normal:
1101 		case RPASS_NonShadow:
1102 			Drawer->DrawAliasModel(Md2Org, Md2Angle, Offset, Scale,
1103 				SubMdl.Model, Md2Frame, Md2NextFrame, GTextureManager(SkinID),
1104 				Trans, ColourMap, Md2Light, Fade, Md2Alpha, Additive,
1105 				IsViewModel, smooth_inter, Interpolate);
1106 			break;
1107 
1108 		case RPASS_Ambient:
1109 			Drawer->DrawAliasModelAmbient(Md2Org, Md2Angle, Offset, Scale,
1110 				SubMdl.Model, Md2Frame, Md2NextFrame, GTextureManager(SkinID),
1111 				Md2Light, smooth_inter, Interpolate);
1112 			break;
1113 
1114 		case RPASS_ShadowVolumes:
1115 			Drawer->DrawAliasModelShadow(Md2Org, Md2Angle, Offset, Scale,
1116 				SubMdl.Model, Md2Frame, Md2NextFrame, smooth_inter, Interpolate,
1117 				LightPos, LightRadius);
1118 			break;
1119 
1120 		case RPASS_Light:
1121 			Drawer->DrawAliasModelLight(Md2Org, Md2Angle, Offset, Scale,
1122 				SubMdl.Model, Md2Frame, Md2NextFrame, GTextureManager(SkinID),
1123 				smooth_inter, Interpolate);
1124 			break;
1125 
1126 		case RPASS_Textures:
1127 			Drawer->DrawAliasModelTextures(Md2Org, Md2Angle, Offset, Scale,
1128 				SubMdl.Model, Md2Frame, Md2NextFrame, GTextureManager(SkinID),
1129 				Trans, ColourMap, smooth_inter, Interpolate);
1130 			break;
1131 
1132 		case RPASS_Fog:
1133 			Drawer->DrawAliasModelFog(Md2Org, Md2Angle, Offset, Scale,
1134 				SubMdl.Model, Md2Frame, Md2NextFrame, GTextureManager(SkinID),
1135 				Fade, smooth_inter, Interpolate);
1136 			break;
1137 		}
1138 	}
1139 	unguard;
1140 }
1141 
1142 //==========================================================================
1143 //
1144 //	VRenderLevelShared::DrawAliasModel
1145 //
1146 //==========================================================================
1147 
DrawAliasModel(const TVec & Org,const TAVec & Angles,float ScaleX,float ScaleY,VModel * Mdl,int Frame,int NextFrame,VTextureTranslation * Trans,int Version,vuint32 Light,vuint32 Fade,float Alpha,bool Additive,bool IsViewModel,float Inter,bool Interpolate,ERenderPass Pass)1148 bool VRenderLevelShared::DrawAliasModel(const TVec& Org, const TAVec& Angles,
1149 	float ScaleX, float ScaleY, VModel* Mdl, int Frame, int NextFrame,
1150 	VTextureTranslation* Trans, int Version, vuint32 Light, vuint32 Fade,
1151 	float Alpha, bool Additive, bool IsViewModel, float Inter, bool Interpolate,
1152 	ERenderPass Pass)
1153 {
1154 	guard(VRenderLevelShared::DrawAliasModel);
1155 	int FIdx = FindFrame(*Mdl->DefaultClass, Frame, Inter);
1156 	if (FIdx == -1)
1157 	{
1158 		return false;
1159 	}
1160 	float InterpFrac;
1161 	int NFIdx = FindNextFrame(*Mdl->DefaultClass, FIdx, NextFrame, Inter,
1162 		InterpFrac);
1163 	if (NFIdx == -1)
1164 	{
1165 		NFIdx = FIdx;
1166 		Interpolate = false;
1167 	}
1168 
1169 	DrawModel(Level, Org, Angles, ScaleX, ScaleY, *Mdl->DefaultClass, FIdx,
1170 		NFIdx, Trans, ColourMap, Version, Light, Fade, Alpha, Additive,
1171 		IsViewModel, InterpFrac, Interpolate, CurrLightPos, CurrLightRadius,
1172 		Pass);
1173 	return true;
1174 	unguard;
1175 }
1176 
1177 //==========================================================================
1178 //
1179 //	VRenderLevelShared::DrawAliasModel
1180 //
1181 //==========================================================================
1182 
DrawAliasModel(const TVec & Org,const TAVec & Angles,float ScaleX,float ScaleY,VState * State,VState * NextState,VTextureTranslation * Trans,int Version,vuint32 Light,vuint32 Fade,float Alpha,bool Additive,bool IsViewModel,float Inter,bool Interpolate,ERenderPass Pass)1183 bool VRenderLevelShared::DrawAliasModel(const TVec& Org, const TAVec& Angles,
1184 	float ScaleX, float ScaleY, VState* State, VState* NextState,
1185 	VTextureTranslation* Trans, int Version, vuint32 Light, vuint32 Fade,
1186 	float Alpha, bool Additive, bool IsViewModel, float Inter, bool Interpolate,
1187 	ERenderPass Pass)
1188 {
1189 	guard(VRenderLevelShared::DrawAliasModel);
1190 	VClassModelScript* Cls = NULL;
1191 	for (int i = 0; i < ClassModels.Num(); i++)
1192 	{
1193 		if (ClassModels[i]->Name == State->Outer->Name)
1194 		{
1195 			Cls = ClassModels[i];
1196 		}
1197 	}
1198 	if (!Cls)
1199 	{
1200 		return false;
1201 	}
1202 
1203 	int FIdx = FindFrame(*Cls, State->InClassIndex, Inter);
1204 	if (FIdx == -1)
1205 	{
1206 		return false;
1207 	}
1208 
1209 	float InterpFrac;
1210 	int NFIdx = FindNextFrame(*Cls, FIdx, NextState->InClassIndex, Inter,
1211 		InterpFrac);
1212 	if (NFIdx == -1)
1213 	{
1214 		NFIdx = FIdx;
1215 		Interpolate = false;
1216 	}
1217 
1218 	DrawModel(Level, Org, Angles, ScaleX, ScaleY, *Cls, FIdx, NFIdx, Trans,
1219 		ColourMap, Version, Light, Fade, Alpha, Additive, IsViewModel,
1220 		InterpFrac, Interpolate, CurrLightPos, CurrLightRadius, Pass);
1221 	return true;
1222 	unguard;
1223 }
1224 
1225 //==========================================================================
1226 //
1227 //	VRenderLevelShared::DrawEntityModel
1228 //
1229 //==========================================================================
1230 
DrawEntityModel(VEntity * Ent,vuint32 Light,vuint32 Fade,float Alpha,bool Additive,float Inter,ERenderPass Pass)1231 bool VRenderLevelShared::DrawEntityModel(VEntity* Ent, vuint32 Light, vuint32 Fade,
1232 	float Alpha, bool Additive, float Inter, ERenderPass Pass)
1233 {
1234 	guard(VRenderLevelShared::DrawEntityModel);
1235 	VState* DispState = (Ent->EntityFlags & VEntity::EF_UseDispState) ?
1236 		Ent->DispState : Ent->State;
1237 	// Check if we want to interpolate model frames
1238 	bool Interpolate;
1239 	if (!r_interpolate_frames)
1240 	{
1241 		Interpolate = false;
1242 	}
1243 	else
1244 	{
1245 		Interpolate = true;
1246 	}
1247 	if (Ent->EntityFlags & VEntity::EF_FixedModel)
1248 	{
1249 		if (!FL_FileExists(VStr("models/") + Ent->FixedModelName))
1250 		{
1251 			GCon->Logf("Can't find %s", *Ent->FixedModelName);
1252 			return false;
1253 		}
1254 		VModel* Mdl = Mod_FindName(VStr("models/") + Ent->FixedModelName);
1255 		if (!Mdl)
1256 		{
1257 			return false;
1258 		}
1259 		return DrawAliasModel(Ent->Origin - TVec(0, 0, Ent->FloorClip),
1260 			Ent->Angles, Ent->ScaleX, Ent->ScaleY, Mdl,
1261 			DispState->InClassIndex,
1262 			DispState->NextState ? DispState->NextState->InClassIndex :
1263 			DispState->InClassIndex, GetTranslation(Ent->Translation),
1264 			Ent->ModelVersion, Light, Fade, Alpha, Additive, false, Inter,
1265 			Interpolate, Pass);
1266 	}
1267 	else
1268 	{
1269 		return DrawAliasModel(Ent->Origin - TVec(0, 0, Ent->FloorClip),
1270 			Ent->Angles, Ent->ScaleX, Ent->ScaleY, DispState,
1271 			DispState->NextState ? DispState->NextState : DispState,
1272 			GetTranslation(Ent->Translation), Ent->ModelVersion, Light, Fade,
1273 			Alpha, Additive, false, Inter, Interpolate, Pass);
1274 	}
1275 	unguard;
1276 }
1277 
1278 //==========================================================================
1279 //
1280 //	VRenderLevelShared::CheckAliasModelFrame
1281 //
1282 //==========================================================================
1283 
CheckAliasModelFrame(VEntity * Ent,float Inter)1284 bool VRenderLevelShared::CheckAliasModelFrame(VEntity* Ent, float Inter)
1285 {
1286 	guard(VRenderLevelShared::CheckAliasModelFrame);
1287 	if (Ent->EntityFlags & VEntity::EF_FixedModel)
1288 	{
1289 		if (!FL_FileExists(VStr("models/") + Ent->FixedModelName))
1290 		{
1291 			return false;
1292 		}
1293 		VModel* Mdl = Mod_FindName(VStr("models/") + Ent->FixedModelName);
1294 		if (!Mdl)
1295 		{
1296 			return false;
1297 		}
1298 		return FindFrame(*Mdl->DefaultClass, Ent->State->InClassIndex, Inter) != -1;
1299 	}
1300 	else
1301 	{
1302 		VClassModelScript* Cls = NULL;
1303 		for (int i = 0; i < ClassModels.Num(); i++)
1304 		{
1305 			if (ClassModels[i]->Name == Ent->State->Outer->Name)
1306 			{
1307 				Cls = ClassModels[i];
1308 			}
1309 		}
1310 		if (!Cls)
1311 		{
1312 			return false;
1313 		}
1314 		return FindFrame(*Cls, Ent->State->InClassIndex, Inter) != -1;
1315 	}
1316 	unguard;
1317 }
1318 
1319 //==========================================================================
1320 //
1321 //	R_DrawModelFrame
1322 //
1323 //==========================================================================
1324 
R_DrawModelFrame(const TVec & Origin,float Angle,VModel * Model,int Frame,int NextFrame,const char * Skin,int TranslStart,int TranslEnd,int Colour,float Inter)1325 void R_DrawModelFrame(const TVec& Origin, float Angle, VModel* Model,
1326 	int Frame, int NextFrame, const char* Skin, int TranslStart,
1327 	int TranslEnd, int Colour, float Inter)
1328 {
1329 	guard(R_DrawModelFrame);
1330 	bool Interpolate = true;
1331 	int FIdx = FindFrame(*Model->DefaultClass, Frame, Inter);
1332 	if (FIdx == -1)
1333 	{
1334 		return;
1335 	}
1336 
1337 	float InterpFrac;
1338 	int NFIdx = FindNextFrame(*Model->DefaultClass, FIdx, NextFrame, Inter,
1339 		InterpFrac);
1340 	if (NFIdx == -1)
1341 	{
1342 		NFIdx = 0;
1343 		Interpolate = false;
1344 	}
1345 
1346 	viewangles.yaw = 180;
1347 	viewangles.pitch = 0;
1348 	viewangles.roll = 0;
1349 	AngleVectors(viewangles, viewforward, viewright, viewup);
1350 	vieworg = TVec(0, 0, 0);
1351 
1352 	refdef_t	rd;
1353 
1354 	rd.x = 0;
1355 	rd.y = 0;
1356 	rd.width = ScreenWidth;
1357 	rd.height = ScreenHeight;
1358 	rd.fovx = tan(DEG2RAD(90) / 2);
1359 	rd.fovy = rd.fovx * 3.0 / 4.0;
1360 	rd.drawworld = false;
1361 	rd.DrawCamera = false;
1362 
1363 	Drawer->SetupView(NULL, &rd);
1364 	Drawer->SetupViewOrg();
1365 
1366 	TAVec Angles;
1367 	Angles.yaw = Angle;
1368 	Angles.pitch = 0;
1369 	Angles.roll = 0;
1370 
1371 	DrawModel(NULL, Origin, Angles, 1.0, 1.0, *Model->DefaultClass, FIdx,
1372 		NFIdx, R_GetCachedTranslation(R_SetMenuPlayerTrans(TranslStart,
1373 		TranslEnd, Colour), NULL), 0, 0, 0xffffffff, 0, 1.0, false, false,
1374 		InterpFrac, Interpolate, TVec(), 0, RPASS_Normal);
1375 
1376 	Drawer->EndView();
1377 	unguard;
1378 }
1379 
1380 //==========================================================================
1381 //
1382 //	R_DrawStateModelFrame
1383 //
1384 //==========================================================================
1385 
R_DrawStateModelFrame(VState * State,VState * NextState,float Inter,const TVec & Origin,float Angle)1386 bool R_DrawStateModelFrame(VState* State, VState* NextState, float Inter,
1387 	 const TVec& Origin, float Angle)
1388 {
1389 	VClassModelScript* Cls = NULL;
1390 	bool Interpolate = true;
1391 	for (int i = 0; i < ClassModels.Num(); i++)
1392 	{
1393 		if (ClassModels[i]->Name == State->Outer->Name)
1394 		{
1395 			Cls = ClassModels[i];
1396 		}
1397 	}
1398 	if (!Cls)
1399 	{
1400 		return false;
1401 	}
1402 	int FIdx = FindFrame(*Cls, State->InClassIndex, Inter);
1403 	if (FIdx == -1)
1404 	{
1405 		return false;
1406 	}
1407 	float InterpFrac;
1408 	int NFIdx = FindNextFrame(*Cls, FIdx, NextState->InClassIndex, Inter,
1409 		InterpFrac);
1410 	if (NFIdx == -1)
1411 	{
1412 		NFIdx = 0;
1413 		Interpolate = false;
1414 	}
1415 
1416 	viewangles.yaw = 180;
1417 	viewangles.pitch = 0;
1418 	viewangles.roll = 0;
1419 	AngleVectors(viewangles, viewforward, viewright, viewup);
1420 	vieworg = TVec(0, 0, 0);
1421 
1422 	refdef_t	rd;
1423 
1424 	rd.x = 0;
1425 	rd.y = 0;
1426 	rd.width = ScreenWidth;
1427 	rd.height = ScreenHeight;
1428 	rd.fovx = tan(DEG2RAD(90) / 2);
1429 	rd.fovy = rd.fovx * rd.height / rd.width / PixelAspect;
1430 	rd.drawworld = false;
1431 	rd.DrawCamera = false;
1432 
1433 	Drawer->SetupView(NULL, &rd);
1434 	Drawer->SetupViewOrg();
1435 
1436 	TAVec Angles;
1437 	Angles.yaw = Angle;
1438 	Angles.pitch = 0;
1439 	Angles.roll = 0;
1440 
1441 	DrawModel(NULL, Origin, Angles, 1.0, 1.0, *Cls, FIdx, NFIdx, NULL, 0, 0,
1442 		0xffffffff, 0, 1.0, false, false, InterpFrac, Interpolate,
1443 		TVec(), 0, RPASS_Normal);
1444 
1445 	Drawer->EndView();
1446 	return true;
1447 }
1448