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