1 /*
2 ===========================================================================
3 Copyright (C) 2000 - 2013, Raven Software, Inc.
4 Copyright (C) 2001 - 2013, Activision, Inc.
5 Copyright (C) 2013 - 2015, OpenJK contributors
6 
7 This file is part of the OpenJK source code.
8 
9 OpenJK is free software; you can redistribute it and/or modify it
10 under the terms of the GNU General Public License version 2 as
11 published by the Free Software Foundation.
12 
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16 GNU General Public License for more details.
17 
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, see <http://www.gnu.org/licenses/>.
20 ===========================================================================
21 */
22 
23 #include "../server/exe_headers.h"
24 
25 #ifndef __Q_SHARED_H
26 	#include "../qcommon/q_shared.h"
27 #endif
28 
29 #include "tr_common.h"
30 
31 #if !defined(TR_LOCAL_H)
32 	#include "tr_local.h"
33 #endif
34 
35 #include "qcommon/matcomp.h"
36 
37 #if !defined(G2_H_INC)
38 	#include "../ghoul2/G2.h"
39 #endif
40 
41 #if !defined (MINIHEAP_H_INC)
42 	#include "../qcommon/MiniHeap.h"
43 #endif
44 
45 #define G2_MODEL_OK(g) ((g)&&(g)->mValid&&(g)->aHeader&&(g)->currentModel&&(g)->animModel)
46 
47 #include "../server/server.h"
48 
49 #include <float.h>
50 
51 #include "qcommon/ojk_saved_game_helper.h"
52 
53 #ifdef _G2_GORE
54 #include "../ghoul2/ghoul2_gore.h"
55 
56 #define GORE_TAG_UPPER (256)
57 #define GORE_TAG_MASK (~255)
58 
59 static int CurrentTag=GORE_TAG_UPPER+1;
60 static int CurrentTagUpper=GORE_TAG_UPPER;
61 
62 static std::map<int,GoreTextureCoordinates> GoreRecords;
63 static std::map<std::pair<int,int>,int> GoreTagsTemp; // this is a surface index to gore tag map used only
64 								  // temporarily during the generation phase so we reuse gore tags per LOD
65 int goreModelIndex;
66 
67 static cvar_t *cg_g2MarksAllModels=NULL;
68 
69 GoreTextureCoordinates *FindGoreRecord(int tag);
DestroyGoreTexCoordinates(int tag)70 static inline void DestroyGoreTexCoordinates(int tag)
71 {
72 	GoreTextureCoordinates *gTC = FindGoreRecord(tag);
73 	if (!gTC)
74 	{
75 		return;
76 	}
77 	(*gTC).~GoreTextureCoordinates();
78 	//I don't know what's going on here, it should call the destructor for
79 	//this when it erases the record but sometimes it doesn't. -rww
80 }
81 
82 //TODO: This needs to be set via a scalability cvar with some reasonable minimum value if pgore is used at all
83 #define MAX_GORE_RECORDS (500)
84 
AllocGoreRecord()85 int AllocGoreRecord()
86 {
87 	while (GoreRecords.size()>MAX_GORE_RECORDS)
88 	{
89 		int tagHigh=(*GoreRecords.begin()).first&GORE_TAG_MASK;
90 		std::map<int,GoreTextureCoordinates>::iterator it;
91 		GoreTextureCoordinates *gTC;
92 
93 		it = GoreRecords.begin();
94 		gTC = &(*it).second;
95 
96 		if (gTC)
97 		{
98 			gTC->~GoreTextureCoordinates();
99 		}
100 		GoreRecords.erase(GoreRecords.begin());
101 		while (GoreRecords.size())
102 		{
103 			if (((*GoreRecords.begin()).first&GORE_TAG_MASK)!=tagHigh)
104 			{
105 				break;
106 			}
107 			it = GoreRecords.begin();
108 			gTC = &(*it).second;
109 
110 			if (gTC)
111 			{
112 				gTC->~GoreTextureCoordinates();
113 			}
114 			GoreRecords.erase(GoreRecords.begin());
115 		}
116 	}
117 	int ret=CurrentTag;
118 	GoreRecords[CurrentTag]=GoreTextureCoordinates();
119 	CurrentTag++;
120 	return ret;
121 }
122 
ResetGoreTag()123 void ResetGoreTag()
124 {
125 	GoreTagsTemp.clear();
126 	CurrentTag=CurrentTagUpper;
127 	CurrentTagUpper+=GORE_TAG_UPPER;
128 }
129 
FindGoreRecord(int tag)130 GoreTextureCoordinates *FindGoreRecord(int tag)
131 {
132 	std::map<int,GoreTextureCoordinates>::iterator i=GoreRecords.find(tag);
133 	if (i!=GoreRecords.end())
134 	{
135 		return &(*i).second;
136 	}
137 	return 0;
138 }
139 
G2_GetGoreRecord(int tag)140 void *G2_GetGoreRecord(int tag)
141 {
142 	return FindGoreRecord(tag);
143 }
144 
DeleteGoreRecord(int tag)145 void DeleteGoreRecord(int tag)
146 {
147 	DestroyGoreTexCoordinates(tag);
148 	GoreRecords.erase(tag);
149 }
150 
151 static int CurrentGoreSet=1; // this is a UUID for gore sets
152 static std::map<int,CGoreSet *> GoreSets; // map from uuid to goreset
153 
FindGoreSet(int goreSetTag)154 CGoreSet *FindGoreSet(int goreSetTag)
155 {
156 	std::map<int,CGoreSet *>::iterator f=GoreSets.find(goreSetTag);
157 	if (f!=GoreSets.end())
158 	{
159 		return (*f).second;
160 	}
161 	return 0;
162 }
163 
NewGoreSet()164 CGoreSet *NewGoreSet()
165 {
166 	CGoreSet *ret=new CGoreSet(CurrentGoreSet++);
167 	GoreSets[ret->mMyGoreSetTag]=ret;
168 	ret->mRefCount = 1;
169 	return ret;
170 }
171 
DeleteGoreSet(int goreSetTag)172 void DeleteGoreSet(int goreSetTag)
173 {
174 	std::map<int,CGoreSet *>::iterator f=GoreSets.find(goreSetTag);
175 	if (f!=GoreSets.end())
176 	{
177 		if ( (*f).second->mRefCount == 0 || (*f).second->mRefCount - 1 == 0 )
178 		{
179 			delete (*f).second;
180 			GoreSets.erase(f);
181 		}
182 		else
183 		{
184 			(*f).second->mRefCount--;
185 		}
186 	}
187 }
188 
189 
~CGoreSet()190 CGoreSet::~CGoreSet()
191 {
192 	std::multimap<int,SGoreSurface>::iterator i;
193 	for (i=mGoreRecords.begin();i!=mGoreRecords.end();++i)
194 	{
195 		DeleteGoreRecord((*i).second.mGoreTag);
196 	}
197 };
198 #endif
199 
200 extern mdxaBone_t		worldMatrix;
201 extern mdxaBone_t		worldMatrixInv;
202 
203 const mdxaBone_t &EvalBoneCache(int index,CBoneCache *boneCache);
204 class CTraceSurface
205 {
206 public:
207 	int					surfaceNum;
208 	surfaceInfo_v		&rootSList;
209 	const model_t		*currentModel;
210 	const int			lod;
211 	vec3_t		rayStart;
212 	vec3_t		rayEnd;
213 	CCollisionRecord	*collRecMap;
214 	const int			entNum;
215 	const int			modelIndex;
216 	const skin_t		*skin;
217 	const shader_t		*cust_shader;
218 	intptr_t			*TransformedVertsArray;
219 	const EG2_Collision	eG2TraceType;
220 	bool				hitOne;
221 	float				m_fRadius;
222 
223 #ifdef _G2_GORE
224 	//gore application thing
225 	float				ssize;
226 	float				tsize;
227 	float				theta;
228 	int					goreShader;
229 	CGhoul2Info			*ghoul2info;
230 
231 	//	Procedural-gore application things
232 	SSkinGoreData		*gore;
233 #endif
234 
CTraceSurface(int initsurfaceNum,surfaceInfo_v & initrootSList,const model_t * initcurrentModel,int initlod,vec3_t initrayStart,vec3_t initrayEnd,CCollisionRecord * initcollRecMap,int initentNum,int initmodelIndex,const skin_t * initskin,const shader_t * initcust_shader,intptr_t * initTransformedVertsArray,const EG2_Collision einitG2TraceType,float fRadius,float initssize,float inittsize,float inittheta,int initgoreShader,CGhoul2Info * initghoul2info,SSkinGoreData * initgore)235 	CTraceSurface(
236 		int					initsurfaceNum,
237 		surfaceInfo_v		&initrootSList,
238 		const model_t		*initcurrentModel,
239 		int					initlod,
240 		vec3_t				initrayStart,
241 		vec3_t				initrayEnd,
242 		CCollisionRecord	*initcollRecMap,
243 		int					initentNum,
244 		int					initmodelIndex,
245 		const skin_t		*initskin,
246 		const shader_t		*initcust_shader,
247 		intptr_t			*initTransformedVertsArray,
248 		const EG2_Collision	einitG2TraceType,
249 #ifdef _G2_GORE
250 		float				fRadius,
251 		float				initssize,
252 		float				inittsize,
253 		float				inittheta,
254 		int					initgoreShader,
255 		CGhoul2Info			*initghoul2info,
256 		SSkinGoreData		*initgore
257 #else
258 		float				fRadius
259 #endif
260 		):
261 
262 		surfaceNum(initsurfaceNum),
263 		rootSList(initrootSList),
264 		currentModel(initcurrentModel),
265 		lod(initlod),
266 		collRecMap(initcollRecMap),
267 		entNum(initentNum),
268 		modelIndex(initmodelIndex),
269 		skin(initskin),
270 		cust_shader(initcust_shader),
271 		TransformedVertsArray(initTransformedVertsArray),
272 		eG2TraceType(einitG2TraceType),
273 		hitOne(false),
274 #ifdef _G2_GORE
275 		m_fRadius(fRadius),
276 		ssize(initssize),
277 		tsize(inittsize),
278 		theta(inittheta),
279 		goreShader(initgoreShader),
280 		ghoul2info(initghoul2info),
281 		gore(initgore)
282 #else
283 		m_fRadius(fRadius)
284 #endif
285 		{
286 		VectorCopy(initrayStart, rayStart);
287 		VectorCopy(initrayEnd, rayEnd);
288 	}
289 };
290 
291 // assorted Ghoul 2 functions.
292 // list all surfaces associated with a model
G2_List_Model_Surfaces(const char * fileName)293 void G2_List_Model_Surfaces(const char *fileName)
294 {
295 	int			i, x;
296 	model_t		*mod_m = R_GetModelByHandle(RE_RegisterModel(fileName));
297 	mdxmSurfHierarchy_t	*surf;
298 
299 	surf = (mdxmSurfHierarchy_t *) ( (byte *)mod_m->mdxm + mod_m->mdxm->ofsSurfHierarchy );
300 	mdxmSurface_t *surface = (mdxmSurface_t *)((byte *)mod_m->mdxm + mod_m->mdxm->ofsLODs + sizeof(mdxmLOD_t));
301 
302 	for ( x = 0 ; x < mod_m->mdxm->numSurfaces ; x++)
303 	{
304 		Com_Printf("Surface %i Name %s\n", x, surf->name);
305 		if (r_verbose->value)
306 		{
307 			Com_Printf("Num Descendants %i\n",  surf->numChildren);
308 			for (i=0; i<surf->numChildren; i++)
309 			{
310 				Com_Printf("Descendant %i\n", surf->childIndexes[i]);
311 			}
312 		}
313 		// find the next surface
314   		surf = (mdxmSurfHierarchy_t *)( (byte *)surf + (intptr_t)( &((mdxmSurfHierarchy_t *)0)->childIndexes[ surf->numChildren ] ));
315   		surface =(mdxmSurface_t *)( (byte *)surface + surface->ofsEnd );
316 	}
317 
318 }
319 
320 // list all bones associated with a model
G2_List_Model_Bones(const char * fileName,int frame)321 void G2_List_Model_Bones(const char *fileName, int frame)
322 {
323 	int				x, i;
324 	mdxaSkel_t		*skel;
325 	mdxaSkelOffsets_t	*offsets;
326 	model_t			*mod_m = R_GetModelByHandle(RE_RegisterModel(fileName));
327 	model_t			*mod_a = R_GetModelByHandle(mod_m->mdxm->animIndex);
328 // 	mdxaFrame_t		*aframe=0;
329 //	int				frameSize;
330 	mdxaHeader_t	*header = mod_a->mdxa;
331 
332 	// figure out where the offset list is
333 	offsets = (mdxaSkelOffsets_t *)((byte *)header + sizeof(mdxaHeader_t));
334 
335 //    frameSize = (int)( &((mdxaFrame_t *)0)->boneIndexes[ header->numBones ] );
336 
337 //	aframe = (mdxaFrame_t *)((byte *)header + header->ofsFrames + (frame * frameSize));
338 	// walk each bone and list it's name
339 	for (x=0; x< mod_a->mdxa->numBones; x++)
340 	{
341 		skel = (mdxaSkel_t *)((byte *)header + sizeof(mdxaHeader_t) + offsets->offsets[x]);
342 		Com_Printf("Bone %i Name %s\n", x, skel->name);
343 
344 		Com_Printf("X pos %f, Y pos %f, Z pos %f\n", skel->BasePoseMat.matrix[0][3], skel->BasePoseMat.matrix[1][3], skel->BasePoseMat.matrix[2][3]);
345 
346 		// if we are in verbose mode give us more details
347 		if (r_verbose->value)
348 		{
349 			Com_Printf("Num Descendants %i\n",  skel->numChildren);
350 			for (i=0; i<skel->numChildren; i++)
351 			{
352 				Com_Printf("Num Descendants %i\n",  skel->numChildren);
353 			}
354 		}
355 	}
356 }
357 
358 
359 /************************************************************************************************
360  * G2_GetAnimFileName
361  *    obtain the .gla filename for a model
362  *
363  * Input
364  *    filename of model
365  *
366  * Output
367  *    true if we successfully obtained a filename, false otherwise
368  *
369  ************************************************************************************************/
G2_GetAnimFileName(const char * fileName,char ** filename)370 qboolean G2_GetAnimFileName(const char *fileName, char **filename)
371 {
372 	// find the model we want
373 	model_t				*mod = R_GetModelByHandle(RE_RegisterModel(fileName));
374 
375 	if (mod && mod->mdxm && (mod->mdxm->animName[0] != 0))
376 	{
377 		*filename = mod->mdxm->animName;
378 		return qtrue;
379 	}
380 	return qfalse;
381 }
382 
383 
384 /////////////////////////////////////////////////////////////////////
385 //
386 //	Code for collision detection for models gameside
387 //
388 /////////////////////////////////////////////////////////////////////
389 
G2_DecideTraceLod(CGhoul2Info & ghoul2,int useLod)390 int G2_DecideTraceLod(CGhoul2Info &ghoul2, int useLod)
391 {
392 	int returnLod = useLod;
393 
394    	// if we are overriding the LOD at top level, then we can afford to only check this level of model
395    	if (ghoul2.mLodBias > returnLod)
396    	{
397    		returnLod =  ghoul2.mLodBias;
398    	}
399 	assert(G2_MODEL_OK(&ghoul2));
400 
401 	assert(ghoul2.currentModel);
402 	assert(ghoul2.currentModel->mdxm);
403 	//what about r_lodBias?
404 
405 	// now ensure that we haven't selected a lod that doesn't exist for this model
406 	if ( returnLod >= ghoul2.currentModel->mdxm->numLODs )
407  	{
408  		returnLod = ghoul2.currentModel->mdxm->numLODs - 1;
409  	}
410 
411 	return returnLod;
412 }
413 
R_TransformEachSurface(const mdxmSurface_t * surface,vec3_t scale,CMiniHeap * G2VertSpace,intptr_t * TransformedVertsArray,CBoneCache * boneCache)414 void R_TransformEachSurface( const mdxmSurface_t *surface, vec3_t scale, CMiniHeap *G2VertSpace, intptr_t *TransformedVertsArray,CBoneCache *boneCache)
415 {
416 	int				 j, k;
417 	mdxmVertex_t 	*v;
418 	float			*TransformedVerts;
419 
420 	//
421 	// deform the vertexes by the lerped bones
422 	//
423 	int *piBoneReferences = (int*) ((byte*)surface + surface->ofsBoneReferences);
424 
425 	// alloc some space for the transformed verts to get put in
426 	TransformedVerts = (float *)G2VertSpace->MiniHeapAlloc(surface->numVerts * 5 * 4);
427 	TransformedVertsArray[surface->thisSurfaceIndex] = (intptr_t)TransformedVerts;
428 	if (!TransformedVerts)
429 	{
430 		assert(TransformedVerts);
431 		Com_Error(ERR_DROP, "Ran out of transform space for Ghoul2 Models. Adjust G2_MINIHEAP_SIZE in sv_init.cpp.\n");
432 	}
433 
434 	// whip through and actually transform each vertex
435 	const int numVerts = surface->numVerts;
436 	v = (mdxmVertex_t *) ((byte *)surface + surface->ofsVerts);
437 	mdxmVertexTexCoord_t *pTexCoords = (mdxmVertexTexCoord_t *) &v[numVerts];
438 
439 	// optimisation issue
440 	if ((scale[0] != 1.0) || (scale[1] != 1.0) || (scale[2] != 1.0))
441 	{
442 		for ( j = 0; j < numVerts; j++ )
443 		{
444 			vec3_t			tempVert, tempNormal;
445 //			mdxmWeight_t	*w;
446 
447 			VectorClear( tempVert );
448 			VectorClear( tempNormal );
449 //			w = v->weights;
450 
451 			const int iNumWeights = G2_GetVertWeights( v );
452 
453 			float fTotalWeight = 0.0f;
454 			for ( k = 0 ; k < iNumWeights ; k++ )
455 			{
456 				int		iBoneIndex	= G2_GetVertBoneIndex( v, k );
457 				float	fBoneWeight	= G2_GetVertBoneWeight( v, k, fTotalWeight, iNumWeights );
458 
459 				const mdxaBone_t &bone=EvalBoneCache(piBoneReferences[iBoneIndex],boneCache);
460 
461 				tempVert[0] += fBoneWeight * ( DotProduct( bone.matrix[0], v->vertCoords ) + bone.matrix[0][3] );
462 				tempVert[1] += fBoneWeight * ( DotProduct( bone.matrix[1], v->vertCoords ) + bone.matrix[1][3] );
463 				tempVert[2] += fBoneWeight * ( DotProduct( bone.matrix[2], v->vertCoords ) + bone.matrix[2][3] );
464 
465 				tempNormal[0] += fBoneWeight * DotProduct( bone.matrix[0], v->normal );
466 				tempNormal[1] += fBoneWeight * DotProduct( bone.matrix[1], v->normal );
467 				tempNormal[2] += fBoneWeight * DotProduct( bone.matrix[2], v->normal );
468 			}
469 			int pos = j * 5;
470 
471 			// copy tranformed verts into temp space
472 			TransformedVerts[pos++] = tempVert[0] * scale[0];
473 			TransformedVerts[pos++] = tempVert[1] * scale[1];
474 			TransformedVerts[pos++] = tempVert[2] * scale[2];
475 			// we will need the S & T coors too for hitlocation and hitmaterial stuff
476 			TransformedVerts[pos++] = pTexCoords[j].texCoords[0];
477 			TransformedVerts[pos] = pTexCoords[j].texCoords[1];
478 
479 			v++;// = (mdxmVertex_t *)&v->weights[/*v->numWeights*/surface->maxVertBoneWeights];
480 		}
481 	}
482 	else
483 	{
484 		int pos = 0;
485 	  	for ( j = 0; j < numVerts; j++ )
486 		{
487 			vec3_t			tempVert, tempNormal;
488 //			const mdxmWeight_t	*w;
489 
490 			VectorClear( tempVert );
491 			VectorClear( tempNormal );
492 //			w = v->weights;
493 
494 			const int iNumWeights = G2_GetVertWeights( v );
495 
496 			float fTotalWeight = 0.0f;
497 			for ( k = 0 ; k < iNumWeights ; k++ )
498 			{
499 				int		iBoneIndex	= G2_GetVertBoneIndex( v, k );
500 				float	fBoneWeight	= G2_GetVertBoneWeight( v, k, fTotalWeight, iNumWeights );
501 
502 				const mdxaBone_t &bone=EvalBoneCache(piBoneReferences[iBoneIndex],boneCache);
503 
504 				tempVert[0] += fBoneWeight * ( DotProduct( bone.matrix[0], v->vertCoords ) + bone.matrix[0][3] );
505 				tempVert[1] += fBoneWeight * ( DotProduct( bone.matrix[1], v->vertCoords ) + bone.matrix[1][3] );
506 				tempVert[2] += fBoneWeight * ( DotProduct( bone.matrix[2], v->vertCoords ) + bone.matrix[2][3] );
507 
508 				tempNormal[0] += fBoneWeight * DotProduct( bone.matrix[0], v->normal );
509 				tempNormal[1] += fBoneWeight * DotProduct( bone.matrix[1], v->normal );
510 				tempNormal[2] += fBoneWeight * DotProduct( bone.matrix[2], v->normal );
511 			}
512 
513 			// copy tranformed verts into temp space
514 			TransformedVerts[pos++] = tempVert[0];
515 			TransformedVerts[pos++] = tempVert[1];
516 			TransformedVerts[pos++] = tempVert[2];
517 			// we will need the S & T coors too for hitlocation and hitmaterial stuff
518 			TransformedVerts[pos++] = pTexCoords[j].texCoords[0];
519 			TransformedVerts[pos++] = pTexCoords[j].texCoords[1];
520 
521 			v++;// = (mdxmVertex_t *)&v->weights[/*v->numWeights*/surface->maxVertBoneWeights];
522 		}
523 	}
524 }
525 
G2_TransformSurfaces(int surfaceNum,surfaceInfo_v & rootSList,CBoneCache * boneCache,const model_t * currentModel,int lod,vec3_t scale,CMiniHeap * G2VertSpace,intptr_t * TransformedVertArray,bool secondTimeAround)526 void G2_TransformSurfaces(int surfaceNum, surfaceInfo_v &rootSList,
527 					CBoneCache *boneCache, const model_t *currentModel, int lod, vec3_t scale, CMiniHeap *G2VertSpace, intptr_t *TransformedVertArray, bool secondTimeAround)
528 {
529 	int	i;
530 	assert(currentModel);
531 	assert(currentModel->mdxm);
532 	// back track and get the surfinfo struct for this surface
533 	const mdxmSurface_t			*surface = (mdxmSurface_t *)G2_FindSurface(currentModel, surfaceNum, lod);
534 	const mdxmHierarchyOffsets_t	*surfIndexes = (mdxmHierarchyOffsets_t *)((byte *)currentModel->mdxm + sizeof(mdxmHeader_t));
535 	const mdxmSurfHierarchy_t		*surfInfo = (mdxmSurfHierarchy_t *)((byte *)surfIndexes + surfIndexes->offsets[surface->thisSurfaceIndex]);
536 
537 	// see if we have an override surface in the surface list
538 	const surfaceInfo_t	*surfOverride = G2_FindOverrideSurface(surfaceNum, rootSList);
539 
540 	// really, we should use the default flags for this surface unless it's been overriden
541 	int offFlags = surfInfo->flags;
542 
543   	if (surfOverride)
544 	{
545 		offFlags = surfOverride->offFlags;
546 	}
547 	// if this surface is not off, add it to the shader render list
548 	if (!offFlags)
549 	{
550 
551 		R_TransformEachSurface(surface, scale, G2VertSpace, TransformedVertArray, boneCache);
552 	}
553 
554 	// if we are turning off all descendants, then stop this recursion now
555 	if (offFlags & G2SURFACEFLAG_NODESCENDANTS)
556 	{
557 		return;
558 	}
559 
560 	// now recursively call for the children
561 	for (i=0; i< surfInfo->numChildren; i++)
562 	{
563 		G2_TransformSurfaces(surfInfo->childIndexes[i], rootSList, boneCache, currentModel, lod, scale, G2VertSpace, TransformedVertArray, secondTimeAround);
564 	}
565 }
566 
567 // main calling point for the model transform for collision detection. At this point all of the skeleton has been transformed.
568 #ifdef _G2_GORE
G2_TransformModel(CGhoul2Info_v & ghoul2,const int frameNum,vec3_t scale,CMiniHeap * G2VertSpace,int useLod,bool ApplyGore,SSkinGoreData * gore)569 void G2_TransformModel(CGhoul2Info_v &ghoul2, const int frameNum, vec3_t scale, CMiniHeap *G2VertSpace, int useLod, bool ApplyGore, SSkinGoreData *gore)
570 #else
571 void G2_TransformModel(CGhoul2Info_v &ghoul2, const int frameNum, vec3_t scale, CMiniHeap *G2VertSpace, int useLod)
572 #endif
573 {
574 	int				i, lod;
575 	vec3_t			correctScale;
576 
577 #if !defined(JK2_MODE) || defined(_G2_GORE)
578 	qboolean		firstModelOnly = qfalse;
579 #endif // !JK2_MODE || _G2_GORE
580 
581 #ifndef JK2_MODE
582 	if ( cg_g2MarksAllModels == NULL )
583 	{
584 		cg_g2MarksAllModels = ri.Cvar_Get( "cg_g2MarksAllModels", "0", 0 );
585 	}
586 
587 	if (cg_g2MarksAllModels == NULL
588 		|| !cg_g2MarksAllModels->integer )
589 	{
590 		firstModelOnly = qtrue;
591 	}
592 #endif // !JK2_MODE
593 
594 #ifdef _G2_GORE
595 	if ( gore
596 		&& gore->firstModel > 0 )
597 	{
598 		firstModelOnly = qfalse;
599 	}
600 #endif
601 
602 	VectorCopy(scale, correctScale);
603 	// check for scales of 0 - that's the default I believe
604 	if (!scale[0])
605 	{
606 		correctScale[0] = 1.0;
607 	}
608 	if (!scale[1])
609 	{
610 		correctScale[1] = 1.0;
611 	}
612 	if (!scale[2])
613 	{
614 		correctScale[2] = 1.0;
615 	}
616 
617 	// walk each possible model for this entity and try rendering it out
618 	for (i=0; i<ghoul2.size(); i++)
619 	{
620 		CGhoul2Info &g=ghoul2[i];
621 		// don't bother with models that we don't care about.
622 		if (!g.mValid)
623 		{
624 			continue;
625 		}
626 		assert(g.mBoneCache);
627 		assert(G2_MODEL_OK(&g));
628 		// stop us building this model more than once per frame
629 		g.mMeshFrameNum = frameNum;
630 
631 		// decide the LOD
632 #ifdef _G2_GORE
633 		if (ApplyGore)
634 		{
635 			lod=useLod;
636 			assert(g.currentModel);
637 			if (lod>=g.currentModel->numLods)
638 			{
639 				g.mTransformedVertsArray = 0;
640 				if ( firstModelOnly )
641 				{
642 					// we don't really need to do multiple models for gore.
643 					return;
644 				}
645 				//do the rest
646 				continue;
647 			}
648 		}
649 		else
650 #endif
651 		{
652 			lod = G2_DecideTraceLod(g, useLod);
653 		}
654 
655 		// give us space for the transformed vertex array to be put in
656 		g.mTransformedVertsArray = (intptr_t *)G2VertSpace->MiniHeapAlloc(g.currentModel->mdxm->numSurfaces * sizeof (intptr_t));
657 		if (!g.mTransformedVertsArray)
658 		{
659 			Com_Error(ERR_DROP, "Ran out of transform space for Ghoul2 Models. Adjust G2_MINIHEAP_SIZE in sv_init.cpp.\n");
660 		}
661 
662 		memset(g.mTransformedVertsArray, 0,(g.currentModel->mdxm->numSurfaces * sizeof (intptr_t)));
663 
664 		G2_FindOverrideSurface(-1,g.mSlist); //reset the quick surface override lookup;
665 		// recursively call the model surface transform
666 		G2_TransformSurfaces(g.mSurfaceRoot, g.mSlist, g.mBoneCache,  g.currentModel, lod, correctScale, G2VertSpace, g.mTransformedVertsArray, false);
667 
668 #ifdef _G2_GORE
669 
670 		if (ApplyGore && firstModelOnly )
671 		{
672 			// we don't really need to do multiple models for gore.
673 			break;
674 		}
675 #endif
676 	}
677 }
678 
679 
680 // work out how much space a triangle takes
G2_AreaOfTri(const vec3_t A,const vec3_t B,const vec3_t C)681 static float	G2_AreaOfTri(const vec3_t A, const vec3_t B, const vec3_t C)
682 {
683 	vec3_t	cross, ab, cb;
684 	VectorSubtract(A, B, ab);
685 	VectorSubtract(C, B, cb);
686 
687 	CrossProduct(ab, cb, cross);
688 
689 	return VectorLength(cross);
690 }
691 
692 // actually determine the S and T of the coordinate we hit in a given poly
G2_BuildHitPointST(const vec3_t A,const float SA,const float TA,const vec3_t B,const float SB,const float TB,const vec3_t C,const float SC,const float TC,const vec3_t P,float * s,float * t,float & bary_i,float & bary_j)693 static void G2_BuildHitPointST( const vec3_t A, const float SA, const float TA,
694 						 const vec3_t B, const float SB, const float TB,
695 						 const vec3_t C, const float SC, const float TC,
696 						 const vec3_t P, float *s, float *t,float &bary_i,float &bary_j)
697 {
698 	float	areaABC = G2_AreaOfTri(A, B, C);
699 
700 	float i = G2_AreaOfTri(P, B, C) / areaABC;
701 	bary_i=i;
702 	float j = G2_AreaOfTri(A, P, C) / areaABC;
703 	bary_j=j;
704 	float k = G2_AreaOfTri(A, B, P) / areaABC;
705 
706 	*s = SA * i + SB * j + SC * k;
707 	*t = TA * i + TB * j + TC * k;
708 
709 	*s=fmod(*s, 1);
710 	if (*s< 0)
711 	{
712 		*s+= 1.0;
713 	}
714 
715 	*t=fmod(*t, 1);
716 	if (*t< 0)
717 	{
718 		*t+= 1.0;
719 	}
720 
721 }
722 
723 
724 // routine that works out given a ray whether or not it hits a poly
G2_SegmentTriangleTest(const vec3_t start,const vec3_t end,const vec3_t A,const vec3_t B,const vec3_t C,qboolean backFaces,qboolean frontFaces,vec3_t returnedPoint,vec3_t returnedNormal,float * denom)725 static inline qboolean G2_SegmentTriangleTest( const vec3_t start, const vec3_t end,
726 	const vec3_t A, const vec3_t B, const vec3_t C,
727 	qboolean backFaces,qboolean frontFaces,vec3_t returnedPoint,vec3_t returnedNormal, float *denom)
728 {
729 	static const float tiny=1E-10f;
730 	vec3_t returnedNormalT;
731 	vec3_t edgeAC;
732 
733 	VectorSubtract(C, A, edgeAC);
734 	VectorSubtract(B, A, returnedNormalT);
735 
736 	CrossProduct(returnedNormalT, edgeAC, returnedNormal);
737 
738 	vec3_t ray;
739 	VectorSubtract(end, start, ray);
740 
741 	*denom=DotProduct(ray, returnedNormal);
742 
743 	if (Q_fabs(*denom)<tiny||        // triangle parallel to ray
744 		(!backFaces && *denom>0)||		// not accepting back faces
745 		(!frontFaces && *denom<0))		//not accepting front faces
746 	{
747 		return qfalse;
748 	}
749 
750 	vec3_t toPlane;
751 	VectorSubtract(A, start, toPlane);
752 
753 	float t=DotProduct(toPlane, returnedNormal)/ *denom;
754 
755 	if (t<0.0f||t>1.0f)
756 	{
757 		return qfalse; // off segment
758 	}
759 
760 	VectorScale(ray, t, ray);
761 
762 	VectorAdd(ray, start, returnedPoint);
763 
764 	vec3_t edgePA;
765 	VectorSubtract(A, returnedPoint, edgePA);
766 
767 	vec3_t edgePB;
768 	VectorSubtract(B, returnedPoint, edgePB);
769 
770 	vec3_t edgePC;
771 	VectorSubtract(C, returnedPoint, edgePC);
772 
773 	vec3_t temp;
774 
775 	CrossProduct(edgePA, edgePB, temp);
776 	if (DotProduct(temp, returnedNormal)<0.0f)
777 	{
778 		return qfalse; // off triangle
779 	}
780 
781 	CrossProduct(edgePC, edgePA, temp);
782 	if (DotProduct(temp,returnedNormal)<0.0f)
783 	{
784 		return qfalse; // off triangle
785 	}
786 
787 	CrossProduct(edgePB, edgePC, temp);
788 	if (DotProduct(temp, returnedNormal)<0.0f)
789 	{
790 		return qfalse; // off triangle
791 	}
792 	return qtrue;
793 }
794 
795 #ifdef _G2_GORE
796 struct SVertexTemp
797 {
798 	int flags;
799 	int touch;
800 	int newindex;
801 	float tex[2];
SVertexTempSVertexTemp802 	SVertexTemp()
803 	{
804 		touch=0;
805 	}
806 };
807 
808 #define MAX_GORE_VERTS (3000)
809 static SVertexTemp GoreVerts[MAX_GORE_VERTS];
810 static int GoreIndexCopy[MAX_GORE_VERTS];
811 static int GoreTouch=1;
812 
813 #define MAX_GORE_INDECIES (6000)
814 static int GoreIndecies[MAX_GORE_INDECIES];
815 
816 #define GORE_MARGIN (0.0f)
817 int	G2API_GetTime(int argTime);
818 
819 // now we at poly level, check each model space transformed poly against the model world transfomed ray
G2_GorePolys(const mdxmSurface_t * surface,CTraceSurface & TS,const mdxmSurfHierarchy_t * surfInfo)820 static void G2_GorePolys( const mdxmSurface_t *surface, CTraceSurface &TS, const mdxmSurfHierarchy_t *surfInfo)
821 {
822 	int			j;
823 	vec3_t basis1;
824 	vec3_t basis2;
825 	vec3_t taxis;
826 	vec3_t saxis;
827 
828 	if (!TS.gore)
829 	{
830 		return;
831 	}
832 
833 	if (!TS.gore->useTheta)
834 	{
835 		VectorCopy(TS.gore->uaxis,basis2);
836 		CrossProduct(TS.rayEnd,basis2,basis1);
837 		if (DotProduct(basis1,basis1)<0.005f)
838 		{	//shot dir and slash dir are too close
839 			return;
840 		}
841 	}
842 
843 	if (TS.gore->useTheta)
844 	{
845 		basis2[0]=0.0f;
846 		basis2[1]=0.0f;
847 		basis2[2]=1.0f;
848 
849 		CrossProduct(TS.rayEnd,basis2,basis1);
850 
851 		if (DotProduct(basis1,basis1)<.1f)
852 		{
853 			basis2[0]=0.0f;
854 			basis2[1]=1.0f;
855 			basis2[2]=0.0f;
856 			CrossProduct(TS.rayEnd,basis2,basis1);
857 		}
858 		CrossProduct(TS.rayEnd,basis1,basis2);
859 	}
860 
861 	// Give me a shot direction not a bunch of zeros :) -Gil
862 	assert(DotProduct(basis1,basis1)>.0001f);
863 	assert(DotProduct(basis2,basis2)>.0001f);
864 
865 	VectorNormalize(basis1);
866 	VectorNormalize(basis2);
867 
868 	float c=cos(TS.theta);
869 	float s=sin(TS.theta);
870 
871 	VectorScale(basis1,.5f*c/TS.tsize,taxis);
872 	VectorMA(taxis,.5f*s/TS.tsize,basis2,taxis);
873 
874 	VectorScale(basis1,-.5f*s/TS.ssize,saxis);
875 	VectorMA(saxis,.5f*c/TS.ssize,basis2,saxis);
876 
877 	//fixme, everything above here should be pre-calculated in G2API_AddSkinGore
878 	float *verts = (float *)TS.TransformedVertsArray[surface->thisSurfaceIndex];
879 	int numVerts = surface->numVerts;
880 	int flags=63;
881 	assert(numVerts<MAX_GORE_VERTS);
882 	for ( j = 0; j < numVerts; j++ )
883 	{
884 		int pos=j*5;
885 		vec3_t delta;
886 		delta[0]=verts[pos+0]-TS.rayStart[0];
887 		delta[1]=verts[pos+1]-TS.rayStart[1];
888 		delta[2]=verts[pos+2]-TS.rayStart[2];
889 		float s=DotProduct(delta,saxis)+0.5f;
890 		float t=DotProduct(delta,taxis)+0.5f;
891 		float depth = DotProduct(delta,TS.rayEnd);
892 		int vflags=0;
893 		if (s>GORE_MARGIN)
894 		{
895 			vflags|=1;
896 		}
897 		if (s<1.0f-GORE_MARGIN)
898 		{
899 			vflags|=2;
900 		}
901 		if (t>GORE_MARGIN)
902 		{
903 			vflags|=4;
904 		}
905 		if (t<1.0f-GORE_MARGIN)
906 		{
907 			vflags|=8;
908 		}
909 		if (depth > TS.gore->depthStart)
910 		{
911 			vflags|=16;
912 		}
913 		if (depth < TS.gore->depthEnd)
914 		{
915 			vflags|=32;
916 		}
917 		vflags=(~vflags);
918 		flags&=vflags;
919 		GoreVerts[j].flags=vflags;
920 		GoreVerts[j].tex[0]=s;
921 		GoreVerts[j].tex[1]=t;
922 	}
923 	if (flags)
924 	{
925 		return; // completely off the gore splotch.
926 	}
927 	int				numTris,newNumTris,newNumVerts;
928 	numTris = surface->numTriangles;
929 	mdxmTriangle_t	*tris;
930 	tris = (mdxmTriangle_t *) ((byte *)surface + surface->ofsTriangles);
931 	verts = (float *)TS.TransformedVertsArray[surface->thisSurfaceIndex];
932 	newNumTris=0;
933 	newNumVerts=0;
934 	GoreTouch++;
935 	for ( j = 0; j < numTris; j++ )
936 	{
937 		assert(tris[j].indexes[0]>=0&&tris[j].indexes[0]<numVerts);
938 		assert(tris[j].indexes[1]>=0&&tris[j].indexes[1]<numVerts);
939 		assert(tris[j].indexes[2]>=0&&tris[j].indexes[2]<numVerts);
940 		flags=63&
941 			GoreVerts[tris[j].indexes[0]].flags&
942 			GoreVerts[tris[j].indexes[1]].flags&
943 			GoreVerts[tris[j].indexes[2]].flags;
944 		if (flags)
945 		{
946 			continue;
947 		}
948 		if (!TS.gore->frontFaces || !TS.gore->backFaces)
949 		{
950 			// we need to back/front face cull
951 			vec3_t e1,e2,n;
952 
953 			VectorSubtract(&verts[tris[j].indexes[1]*5],&verts[tris[j].indexes[0]*5],e1);
954 			VectorSubtract(&verts[tris[j].indexes[2]*5],&verts[tris[j].indexes[0]*5],e2);
955 			CrossProduct(e1,e2,n);
956 			if (DotProduct(TS.rayEnd,n)>0.0f)
957 			{
958 				if (!TS.gore->frontFaces)
959 				{
960 					continue;
961 				}
962 			}
963 			else
964 			{
965 				if (!TS.gore->backFaces)
966 				{
967 					continue;
968 				}
969 			}
970 
971 		}
972 
973 		int k;
974 
975 		assert(newNumTris*3+3<MAX_GORE_INDECIES);
976 		for (k=0;k<3;k++)
977 		{
978 			if (GoreVerts[tris[j].indexes[k]].touch==GoreTouch)
979 			{
980 				GoreIndecies[newNumTris*3+k]=GoreVerts[tris[j].indexes[k]].newindex;
981 			}
982 			else
983 			{
984 				GoreVerts[tris[j].indexes[k]].touch=GoreTouch;
985 				GoreVerts[tris[j].indexes[k]].newindex=newNumVerts;
986 				GoreIndecies[newNumTris*3+k]=newNumVerts;
987 				GoreIndexCopy[newNumVerts]=tris[j].indexes[k];
988 				newNumVerts++;
989 			}
990 		}
991 		newNumTris++;
992 	}
993 	if (!newNumVerts)
994 	{
995 		return;
996 	}
997 
998 	int newTag;
999 	std::map<std::pair<int,int>,int>::iterator f=GoreTagsTemp.find(std::make_pair(goreModelIndex,TS.surfaceNum));
1000 	if (f==GoreTagsTemp.end()) // need to generate a record
1001 	{
1002 		newTag=AllocGoreRecord();
1003 		CGoreSet *goreSet=0;
1004 		if (TS.ghoul2info->mGoreSetTag)
1005 		{
1006 			goreSet=FindGoreSet(TS.ghoul2info->mGoreSetTag);
1007 		}
1008 		if (!goreSet)
1009 		{
1010 			goreSet=NewGoreSet();
1011 			TS.ghoul2info->mGoreSetTag=goreSet->mMyGoreSetTag;
1012 		}
1013 		assert(goreSet);
1014 		SGoreSurface add;
1015 		add.shader=TS.goreShader;
1016 		add.mDeleteTime=0;
1017 		if (TS.gore->lifeTime)
1018 		{
1019 			add.mDeleteTime=G2API_GetTime(0) + TS.gore->lifeTime;
1020 		}
1021 		add.mFadeTime = TS.gore->fadeOutTime;
1022 		add.mFadeRGB = TS.gore->fadeRGB;
1023 		add.mGoreTag = newTag;
1024 
1025 		add.mGoreGrowStartTime=G2API_GetTime(0);
1026 		if( TS.gore->growDuration == -1)
1027 		{
1028 			add.mGoreGrowEndTime = -1;    // set this to -1 to disable growing
1029 		}
1030 		else
1031 		{
1032 			add.mGoreGrowEndTime = G2API_GetTime(0) + TS.gore->growDuration;
1033 		}
1034 
1035 		assert(TS.gore->growDuration != 0);
1036 		add.mGoreGrowFactor = ( 1.0f - TS.gore->goreScaleStartFraction) / (float)(TS.gore->growDuration);	//curscale = (curtime-mGoreGrowStartTime)*mGoreGrowFactor;
1037 		add.mGoreGrowOffset = TS.gore->goreScaleStartFraction;
1038 
1039 		goreSet->mGoreRecords.insert(std::make_pair(TS.surfaceNum,add));
1040 		GoreTagsTemp[std::make_pair(goreModelIndex,TS.surfaceNum)]=newTag;
1041 	}
1042 	else
1043 	{
1044 		newTag=(*f).second;
1045 	}
1046 	GoreTextureCoordinates *gore=FindGoreRecord(newTag);
1047 	if (gore)
1048 	{
1049 		assert(sizeof(float)==sizeof(int));
1050 		// data block format:
1051 		unsigned int size=
1052 			sizeof(int)+ // num verts
1053 			sizeof(int)+ // num tris
1054 			sizeof(int)*newNumVerts+ // which verts to copy from original surface
1055 			sizeof(float)*4*newNumVerts+ // storgage for deformed verts
1056 			sizeof(float)*4*newNumVerts+ // storgage for deformed normal
1057 			sizeof(float)*2*newNumVerts+ // texture coordinates
1058 			sizeof(int)*newNumTris*3;  // new indecies
1059 
1060 		int *data=(int *)R_Malloc ( sizeof(int)*size, TAG_GHOUL2, qtrue );
1061 
1062 		if ( gore->tex[TS.lod] )
1063 			R_Free(gore->tex[TS.lod]);
1064 
1065 		gore->tex[TS.lod]=(float *)data;
1066 		*data++=newNumVerts;
1067 		*data++=newNumTris;
1068 
1069 		memcpy(data,GoreIndexCopy,sizeof(int)*newNumVerts);
1070 		data+=newNumVerts*9; // skip verts and normals
1071 		float *fdata=(float *)data;
1072 
1073 		for (j=0;j<newNumVerts;j++)
1074 		{
1075 			*fdata++=GoreVerts[GoreIndexCopy[j]].tex[0];
1076 			*fdata++=GoreVerts[GoreIndexCopy[j]].tex[1];
1077 		}
1078 		data=(int *)fdata;
1079 		memcpy(data,GoreIndecies,sizeof(int)*newNumTris*3);
1080 		data+=newNumTris*3;
1081 		assert((data-(int *)gore->tex[TS.lod])*sizeof(int)==size);
1082 		fdata = (float *)data;
1083 		// build the entity to gore matrix
1084 		VectorCopy(saxis,fdata+0);
1085 		VectorCopy(taxis,fdata+4);
1086 		VectorCopy(TS.rayEnd,fdata+8);
1087 		VectorNormalize(fdata+0);
1088 		VectorNormalize(fdata+4);
1089 		VectorNormalize(fdata+8);
1090 		fdata[3]=-0.5f; // subtract texture center
1091 		fdata[7]=-0.5f;
1092 		fdata[11]=0.0f;
1093 		vec3_t shotOriginInCurrentSpace; // unknown space
1094 		TransformPoint(TS.rayStart,shotOriginInCurrentSpace,(mdxaBone_t *)fdata); // dest middle arg
1095 		// this will insure the shot origin in our unknown space is now the shot origin, making it a known space
1096 		fdata[3]-=shotOriginInCurrentSpace[0];
1097 		fdata[7]-=shotOriginInCurrentSpace[1];
1098 		fdata[11]-=shotOriginInCurrentSpace[2];
1099 		Inverse_Matrix((mdxaBone_t *)fdata,(mdxaBone_t *)(fdata+12));  // dest 2nd arg
1100 		data+=24;
1101 
1102 //		assert((data - (int *)gore->tex[TS.lod]) * sizeof(int) == size);
1103 	}
1104 }
1105 #else
1106 struct SVertexTemp
1107 {
1108 	int flags;
1109 //	int touch;
1110 //	int newindex;
1111 //	float tex[2];
SVertexTempSVertexTemp1112 	SVertexTemp()
1113 	{
1114 //		touch=0;
1115 	}
1116 };
1117 
1118 #define MAX_GORE_VERTS (3000)
1119 static SVertexTemp GoreVerts[MAX_GORE_VERTS];
1120 #endif
1121 
1122 // now we're at poly level, check each model space transformed poly against the model world transfomed ray
G2_TracePolys(const mdxmSurface_t * surface,const mdxmSurfHierarchy_t * surfInfo,CTraceSurface & TS)1123 static bool G2_TracePolys(const mdxmSurface_t *surface, const mdxmSurfHierarchy_t *surfInfo, CTraceSurface &TS)
1124 {
1125 	int				j, numTris;
1126 
1127 	// whip through and actually transform each vertex
1128 	const mdxmTriangle_t *tris = (mdxmTriangle_t *) ((byte *)surface + surface->ofsTriangles);
1129 	const float *verts = (float *)TS.TransformedVertsArray[surface->thisSurfaceIndex];
1130 	numTris = surface->numTriangles;
1131 	for ( j = 0; j < numTris; j++ )
1132 	{
1133 		float			face;
1134 		vec3_t	hitPoint, normal;
1135 		// determine actual coords for this triangle
1136 		const float *point1 = &verts[(tris[j].indexes[0] * 5)];
1137 		const float *point2 = &verts[(tris[j].indexes[1] * 5)];
1138 		const float *point3 = &verts[(tris[j].indexes[2] * 5)];
1139 		// did we hit it?
1140 		if (G2_SegmentTriangleTest(TS.rayStart, TS.rayEnd, point1, point2, point3, qtrue, qtrue, hitPoint, normal, &face))
1141 		{	// find space in the collision records for this record
1142 			int i=0;
1143 			for (; i<MAX_G2_COLLISIONS;i++)
1144 			{
1145 				if (TS.collRecMap[i].mEntityNum == -1)
1146 				{
1147 					CCollisionRecord  	&newCol = TS.collRecMap[i];
1148 					vec3_t			  	distVect;
1149 					float				x_pos = 0, y_pos = 0;
1150 
1151 					newCol.mPolyIndex = j;
1152 					newCol.mEntityNum = TS.entNum;
1153 					newCol.mSurfaceIndex = surface->thisSurfaceIndex;
1154 					newCol.mModelIndex = TS.modelIndex;
1155 					if (face>0)
1156 					{
1157 						newCol.mFlags = G2_FRONTFACE;
1158 					}
1159 					else
1160 					{
1161 						newCol.mFlags = G2_BACKFACE;
1162 					}
1163 
1164 					VectorSubtract(hitPoint, TS.rayStart, distVect);
1165 					newCol.mDistance = VectorLength(distVect);
1166 					assert( !Q_isnan(newCol.mDistance) );
1167 
1168 					// put the hit point back into world space
1169 					TransformAndTranslatePoint(hitPoint, newCol.mCollisionPosition, &worldMatrix);
1170 
1171 					// transform normal (but don't translate) into world angles
1172 					TransformPoint(normal, newCol.mCollisionNormal, &worldMatrix);
1173 					VectorNormalize(newCol.mCollisionNormal);
1174 
1175 					newCol.mMaterial = newCol.mLocation = 0;
1176 
1177 					// Determine our location within the texture, and barycentric coordinates
1178 					G2_BuildHitPointST(point1, point1[3], point1[4],
1179 									   point2, point2[3], point2[4],
1180 									   point3, point3[3], point3[4],
1181 									   hitPoint, &x_pos, &y_pos,newCol.mBarycentricI,newCol.mBarycentricJ);
1182 
1183 /*
1184 					const shader_t		*shader = 0;
1185 					// now, we know what surface this hit belongs to, we need to go get the shader handle so we can get the correct hit location and hit material info
1186 					if ( cust_shader )
1187 					{
1188 						shader = cust_shader;
1189 					}
1190 					else if ( skin )
1191 					{
1192 						int		j;
1193 
1194 						// match the surface name to something in the skin file
1195 						shader = tr.defaultShader;
1196 						for ( j = 0 ; j < skin->numSurfaces ; j++ )
1197 						{
1198 							// the names have both been lowercased
1199 							if ( !strcmp( skin->surfaces[j]->name, surfInfo->name ) )
1200 							{
1201 								shader = skin->surfaces[j]->shader;
1202 								break;
1203 							}
1204 						}
1205 					}
1206 					else
1207 					{
1208 						shader = R_GetShaderByHandle( surfInfo->shaderIndex );
1209 					}
1210 
1211 					// do we even care to decide what the hit or location area's are? If we don't have them in the shader there is little point
1212 					if ((shader->hitLocation) || (shader->hitMaterial))
1213 					{
1214  						// ok, we have a floating point position. - determine location in data we need to look at
1215 						if (shader->hitLocation)
1216 						{
1217 							newCol.mLocation = *(hitMatReg[shader->hitLocation].loc +
1218 												((int)(y_pos * hitMatReg[shader->hitLocation].height) * hitMatReg[shader->hitLocation].width) +
1219 												((int)(x_pos * hitMatReg[shader->hitLocation].width)));
1220 							Com_Printf("G2_TracePolys hit location: %d\n", newCol.mLocation);
1221 						}
1222 
1223 						if (shader->hitMaterial)
1224 						{
1225 							newCol.mMaterial = *(hitMatReg[shader->hitMaterial].loc +
1226 												((int)(y_pos * hitMatReg[shader->hitMaterial].height) * hitMatReg[shader->hitMaterial].width) +
1227 												((int)(x_pos * hitMatReg[shader->hitMaterial].width)));
1228 						}
1229 					}
1230 */
1231 					// exit now if we should
1232 					if (TS.eG2TraceType == G2_RETURNONHIT)
1233 					{
1234 						TS.hitOne = true;
1235 						return true;
1236 					}
1237 
1238 					break;
1239 				}
1240 			}
1241 			if (i == MAX_G2_COLLISIONS)
1242 			{
1243 				assert(i!=MAX_G2_COLLISIONS);		// run out of collision record space - will probalbly never happen
1244 				TS.hitOne = true;	//force stop recursion
1245 				return true;	// return true to avoid wasting further time, but no hit will result without a record
1246 			}
1247 		}
1248 	}
1249 	return false;
1250 }
1251 
1252 
1253 // now we're at poly level, check each model space transformed poly against the model world transfomed ray
G2_RadiusTracePolys(const mdxmSurface_t * surface,CTraceSurface & TS)1254 static bool G2_RadiusTracePolys(
1255 								const mdxmSurface_t *surface,
1256 								CTraceSurface &TS
1257 								)
1258 {
1259 	int		j;
1260 	vec3_t basis1;
1261 	vec3_t basis2;
1262 	vec3_t taxis;
1263 	vec3_t saxis;
1264 
1265 	basis2[0]=0.0f;
1266 	basis2[1]=0.0f;
1267 	basis2[2]=1.0f;
1268 
1269 	vec3_t v3RayDir;
1270 	VectorSubtract(TS.rayEnd, TS.rayStart, v3RayDir);
1271 
1272 	CrossProduct(v3RayDir,basis2,basis1);
1273 
1274 	if (DotProduct(basis1,basis1)<.1f)
1275 	{
1276 		basis2[0]=0.0f;
1277 		basis2[1]=1.0f;
1278 		basis2[2]=0.0f;
1279 		CrossProduct(v3RayDir,basis2,basis1);
1280 	}
1281 
1282 	CrossProduct(v3RayDir,basis1,basis2);
1283 	// Give me a shot direction not a bunch of zeros :) -Gil
1284 //	assert(DotProduct(basis1,basis1)>.0001f);
1285 //	assert(DotProduct(basis2,basis2)>.0001f);
1286 
1287 	VectorNormalize(basis1);
1288 	VectorNormalize(basis2);
1289 
1290 	const float c=cos(0.0f);//theta
1291 	const float s=sin(0.0f);//theta
1292 
1293 	VectorScale(basis1, 0.5f * c / TS.m_fRadius,taxis);
1294 	VectorMA(taxis,     0.5f * s / TS.m_fRadius,basis2,taxis);
1295 
1296 	VectorScale(basis1,-0.5f * s /TS.m_fRadius,saxis);
1297 	VectorMA(    saxis, 0.5f * c /TS.m_fRadius,basis2,saxis);
1298 
1299 	const float * const verts = (float *)TS.TransformedVertsArray[surface->thisSurfaceIndex];
1300 	const int numVerts = surface->numVerts;
1301 
1302 	int flags=63;
1303 	//rayDir/=lengthSquared(raydir);
1304 	const float f = VectorLengthSquared(v3RayDir);
1305 	v3RayDir[0]/=f;
1306 	v3RayDir[1]/=f;
1307 	v3RayDir[2]/=f;
1308 
1309 	for ( j = 0; j < numVerts; j++ )
1310 	{
1311 		const int pos=j*5;
1312 		vec3_t delta;
1313 		delta[0]=verts[pos+0]-TS.rayStart[0];
1314 		delta[1]=verts[pos+1]-TS.rayStart[1];
1315 		delta[2]=verts[pos+2]-TS.rayStart[2];
1316 		const float s=DotProduct(delta,saxis)+0.5f;
1317 		const float t=DotProduct(delta,taxis)+0.5f;
1318 		const float u=DotProduct(delta,v3RayDir);
1319 		int vflags=0;
1320 
1321 		if (s>0)
1322 		{
1323 			vflags|=1;
1324 		}
1325 		if (s<1)
1326 		{
1327 			vflags|=2;
1328 		}
1329 		if (t>0)
1330 		{
1331 			vflags|=4;
1332 		}
1333 		if (t<1)
1334 		{
1335 			vflags|=8;
1336 		}
1337 		if (u>0)
1338 		{
1339 			vflags|=16;
1340 		}
1341 		if (u<1)
1342 		{
1343 			vflags|=32;
1344 		}
1345 
1346 		vflags=(~vflags);
1347 		flags&=vflags;
1348 		GoreVerts[j].flags=vflags;
1349 	}
1350 
1351 	if (flags)
1352 	{
1353 		return false; // completely off the gore splotch  (so presumably hit nothing? -Ste)
1354 	}
1355 	const int numTris = surface->numTriangles;
1356 	const mdxmTriangle_t * const tris = (mdxmTriangle_t *) ((byte *)surface + surface->ofsTriangles);
1357 
1358 	for ( j = 0; j < numTris; j++ )
1359 	{
1360 		assert(tris[j].indexes[0]>=0&&tris[j].indexes[0]<numVerts);
1361 		assert(tris[j].indexes[1]>=0&&tris[j].indexes[1]<numVerts);
1362 		assert(tris[j].indexes[2]>=0&&tris[j].indexes[2]<numVerts);
1363 		flags=63&
1364 			GoreVerts[tris[j].indexes[0]].flags&
1365 			GoreVerts[tris[j].indexes[1]].flags&
1366 			GoreVerts[tris[j].indexes[2]].flags;
1367 		if (flags)
1368 		{
1369 			continue;
1370 		}
1371 		else
1372 		{
1373 			// we hit a triangle, so init a collision record...
1374 			//
1375 			int i = 0;
1376 			for (; i<MAX_G2_COLLISIONS;i++)
1377 			{
1378 				if (TS.collRecMap[i].mEntityNum == -1)
1379 				{
1380 					CCollisionRecord  	&newCol = TS.collRecMap[i];
1381 
1382 					newCol.mPolyIndex = j;
1383 					newCol.mEntityNum = TS.entNum;
1384 					newCol.mSurfaceIndex = surface->thisSurfaceIndex;
1385 					newCol.mModelIndex = TS.modelIndex;
1386 //					if (face>0)
1387 //					{
1388 						newCol.mFlags = G2_FRONTFACE;
1389 //					}
1390 //					else
1391 //					{
1392 //						newCol.mFlags = G2_BACKFACE;
1393 //					}
1394 
1395 					//get normal from triangle
1396 					const float *A = &verts[(tris[j].indexes[0] * 5)];
1397 					const float *B = &verts[(tris[j].indexes[1] * 5)];
1398 					const float *C = &verts[(tris[j].indexes[2] * 5)];
1399 					vec3_t normal;
1400 					vec3_t edgeAC, edgeBA;
1401 
1402 					VectorSubtract(C, A, edgeAC);
1403 					VectorSubtract(B, A, edgeBA);
1404 					CrossProduct(edgeBA, edgeAC, normal);
1405 
1406 					// transform normal (but don't translate) into world angles
1407 					TransformPoint(normal, newCol.mCollisionNormal, &worldMatrix);
1408 					VectorNormalize(newCol.mCollisionNormal);
1409 
1410 					newCol.mMaterial = newCol.mLocation = 0;
1411 					// exit now if we should
1412 					if (TS.eG2TraceType == G2_RETURNONHIT)
1413 					{
1414 						TS.hitOne = true;
1415 						return true;
1416 					}
1417 
1418 					vec3_t			  distVect;
1419 #if 0
1420 					//i don't know the hitPoint, but let's just assume it's the first vert for now...
1421 					float *hitPoint = (float *)A;
1422 #else
1423 					//yeah, I want the collision point. Let's work out the impact point on the triangle. -rww
1424 					vec3_t hitPoint;
1425 					float side, side2;
1426 					float dist;
1427 					float third = -(A[0]*(B[1]*C[2] - C[1]*B[2]) + B[0]*(C[1]*A[2] - A[1]*C[2]) + C[0]*(A[1]*B[2] - B[1]*A[2]) );
1428 
1429 					VectorSubtract(TS.rayEnd, TS.rayStart, distVect);
1430 					side = normal[0]*TS.rayStart[0] + normal[1]*TS.rayStart[1] + normal[2]*TS.rayStart[2] + third;
1431                     side2 = normal[0]*distVect[0] + normal[1]*distVect[1] + normal[2]*distVect[2];
1432 					if (fabsf(side2)<1E-8f)
1433 					{
1434 						//i don't know the hitPoint, but let's just assume it's the first vert for now...
1435 						VectorSubtract(A, TS.rayStart, distVect);
1436 						dist = VectorLength(distVect);
1437 						VectorSubtract(TS.rayEnd, TS.rayStart, distVect);
1438 						VectorMA(TS.rayStart, dist/VectorLength(distVect), distVect, hitPoint);
1439 					}
1440 					else
1441 					{
1442 						dist = side/side2;
1443 						VectorMA(TS.rayStart, -dist, distVect, hitPoint);
1444 					}
1445 #endif
1446 
1447 					VectorSubtract(hitPoint, TS.rayStart, distVect);
1448 					newCol.mDistance = VectorLength(distVect);
1449 					assert( !Q_isnan(newCol.mDistance) );
1450 
1451 					// put the hit point back into world space
1452 					TransformAndTranslatePoint(hitPoint, newCol.mCollisionPosition, &worldMatrix);
1453 					newCol.mBarycentricI = newCol.mBarycentricJ = 0.0f;
1454 
1455 					break;
1456 				}
1457 			}
1458 			if (i==MAX_G2_COLLISIONS)
1459 			{
1460 				//assert(i!=MAX_G2_COLLISIONS);		// run out of collision record space - happens OFTEN
1461 				TS.hitOne = true;	//force stop recursion
1462 				return true;	// return true to avoid wasting further time, but no hit will result without a record
1463 			}
1464 		}
1465 	}
1466 
1467 	return false;
1468 }
1469 
1470 
1471 // look at a surface and then do the trace on each poly
G2_TraceSurfaces(CTraceSurface & TS)1472 static void G2_TraceSurfaces(CTraceSurface &TS)
1473 {
1474 	int	i;
1475 	// back track and get the surfinfo struct for this surface
1476 	assert(TS.currentModel);
1477 	assert(TS.currentModel->mdxm);
1478 	const mdxmSurface_t		*surface = (mdxmSurface_t *)G2_FindSurface(TS.currentModel, TS.surfaceNum, TS.lod);
1479 	const mdxmHierarchyOffsets_t	*surfIndexes = (mdxmHierarchyOffsets_t *)((byte *)TS.currentModel->mdxm + sizeof(mdxmHeader_t));
1480 	const mdxmSurfHierarchy_t		*surfInfo = (mdxmSurfHierarchy_t *)((byte *)surfIndexes + surfIndexes->offsets[surface->thisSurfaceIndex]);
1481 
1482 	// see if we have an override surface in the surface list
1483 	const surfaceInfo_t	*surfOverride = G2_FindOverrideSurface(TS.surfaceNum, TS.rootSList);
1484 
1485 	// don't allow recursion if we've already hit a polygon
1486 	if (TS.hitOne)
1487 	{
1488 		return;
1489 	}
1490 
1491 	// really, we should use the default flags for this surface unless it's been overriden
1492 	int offFlags = surfInfo->flags;
1493 
1494 	// set the off flags if we have some
1495 	if (surfOverride)
1496 	{
1497 		offFlags = surfOverride->offFlags;
1498 	}
1499 
1500 	// if this surface is not off, try to hit it
1501 	if (!offFlags)
1502 	{
1503 #ifdef _G2_GORE
1504 		if (TS.collRecMap)
1505 		{
1506 #endif
1507 			if (!(Q_fabs(TS.m_fRadius) < 0.1))	// if not a point-trace
1508 			{
1509 				// .. then use radius check
1510 				//
1511 				if (G2_RadiusTracePolys(surface,		// const mdxmSurface_t *surface,
1512 										TS
1513 										)
1514 					&& (TS.eG2TraceType == G2_RETURNONHIT)
1515 					)
1516 				{
1517 					TS.hitOne = true;
1518 					return;
1519 				}
1520 			}
1521 			else
1522 			{
1523 				// go away and trace the polys in this surface
1524 				if (G2_TracePolys(surface, surfInfo, TS)
1525 					&& (TS.eG2TraceType == G2_RETURNONHIT)
1526 					)
1527 				{
1528 					// ok, we hit one, *and* we want to return instantly because the returnOnHit is set
1529 					// so indicate we've hit one, so other surfaces don't get hit and return
1530 					TS.hitOne = true;
1531 					return;
1532 				}
1533 			}
1534 #ifdef _G2_GORE
1535 		}
1536 		else
1537 		{
1538 			G2_GorePolys(surface, TS, surfInfo);
1539 		}
1540 #endif
1541 	}
1542 
1543 	// if we are turning off all descendants, then stop this recursion now
1544 	if (offFlags & G2SURFACEFLAG_NODESCENDANTS)
1545 	{
1546 		return;
1547 	}
1548 
1549 	// now recursively call for the children
1550 	for (i=0; i< surfInfo->numChildren && !TS.hitOne; i++)
1551 	{
1552 		TS.surfaceNum = surfInfo->childIndexes[i];
1553 		G2_TraceSurfaces(TS);
1554 	}
1555 }
1556 
1557 #ifdef _G2_GORE
G2_TraceModels(CGhoul2Info_v & ghoul2,vec3_t rayStart,vec3_t rayEnd,CCollisionRecord * collRecMap,int entNum,EG2_Collision eG2TraceType,int useLod,float fRadius,float ssize,float tsize,float theta,int shader,SSkinGoreData * gore,qboolean skipIfLODNotMatch)1558 void G2_TraceModels(CGhoul2Info_v &ghoul2, vec3_t rayStart, vec3_t rayEnd, CCollisionRecord *collRecMap, int entNum, EG2_Collision eG2TraceType, int useLod, float fRadius, float ssize,float tsize,float theta,int shader, SSkinGoreData *gore, qboolean skipIfLODNotMatch)
1559 #else
1560 void G2_TraceModels(CGhoul2Info_v &ghoul2, vec3_t rayStart, vec3_t rayEnd, CCollisionRecord *collRecMap, int entNum, EG2_Collision eG2TraceType, int useLod, float fRadius)
1561 #endif
1562 {
1563 	int				i, lod;
1564 	skin_t			*skin;
1565 	shader_t		*cust_shader;
1566 #if !defined(JK2_MODE) || defined(_G2_GORE)
1567 	qboolean		firstModelOnly = qfalse;
1568 #endif // !JK2_MODE || _G2_GORE
1569 	int				firstModel = 0;
1570 
1571 #ifndef JK2_MODE
1572 	if ( cg_g2MarksAllModels == NULL )
1573 	{
1574 		cg_g2MarksAllModels = ri.Cvar_Get( "cg_g2MarksAllModels", "0", 0 );
1575 	}
1576 
1577 	if (cg_g2MarksAllModels == NULL
1578 		|| !cg_g2MarksAllModels->integer )
1579 	{
1580 		firstModelOnly = qtrue;
1581 	}
1582 #endif // !JK2_MODE
1583 
1584 #ifdef _G2_GORE
1585 	if ( gore
1586 		&& gore->firstModel > 0 )
1587 	{
1588 		firstModel = gore->firstModel;
1589 		firstModelOnly = qfalse;
1590 	}
1591 #endif
1592 
1593 	// walk each possible model for this entity and try tracing against it
1594 	for (i=firstModel; i<ghoul2.size(); i++)
1595 	{
1596 		CGhoul2Info &g=ghoul2[i];
1597 #ifdef _G2_GORE
1598 		goreModelIndex=i;
1599 		// don't bother with models that we don't care about.
1600 		if (g.mModelindex == -1)
1601 		{
1602 			continue;
1603 		}
1604 #endif
1605 		// don't bother with models that we don't care about.
1606 		if (!g.mValid)
1607 		{
1608 			continue;
1609 		}
1610 		assert(G2_MODEL_OK(&ghoul2[i]));
1611 		// do we really want to collide with this object?
1612 		if (g.mFlags & GHOUL2_NOCOLLIDE)
1613 		{
1614 			continue;
1615 		}
1616 
1617 		if (g.mCustomShader)
1618 		{
1619 			cust_shader = R_GetShaderByHandle(g.mCustomShader );
1620 		}
1621 		else
1622 		{
1623 			cust_shader = NULL;
1624 		}
1625 
1626 		// figure out the custom skin thing
1627 		if ( g.mSkin > 0 && g.mSkin < tr.numSkins )
1628 		{
1629 			skin = R_GetSkinByHandle( g.mSkin );
1630 		}
1631 		else
1632 		{
1633 			skin = NULL;
1634 		}
1635 
1636 		lod = G2_DecideTraceLod(g,useLod);
1637 
1638 #ifndef JK2_MODE
1639 		if ( skipIfLODNotMatch )
1640 		{//we only want to hit this SPECIFIC LOD...
1641 			if ( lod != useLod )
1642 			{//doesn't match, skip this model
1643 				continue;
1644 			}
1645 		}
1646 #endif // !JK2_MODE
1647 
1648 		//reset the quick surface override lookup
1649 		G2_FindOverrideSurface(-1, g.mSlist);
1650 
1651 #ifdef _G2_GORE
1652 		CTraceSurface TS(g.mSurfaceRoot, g.mSlist,  g.currentModel, lod, rayStart, rayEnd, collRecMap, entNum, i, skin, cust_shader, g.mTransformedVertsArray, eG2TraceType, fRadius, ssize, tsize, theta, shader, &g, gore);
1653 #else
1654 		CTraceSurface TS(g.mSurfaceRoot, g.mSlist,  g.currentModel, lod, rayStart, rayEnd, collRecMap, entNum, i, skin, cust_shader, g.mTransformedVertsArray, eG2TraceType, fRadius);
1655 #endif
1656 		// start the surface recursion loop
1657 		G2_TraceSurfaces(TS);
1658 
1659 		// if we've hit one surface on one model, don't bother doing the rest
1660 		if (TS.hitOne)
1661 		{
1662 			break;
1663 		}
1664 #ifdef _G2_GORE
1665 		if ( !collRecMap && firstModelOnly )
1666 		{
1667 			// we don't really need to do multiple models for gore.
1668 			break;
1669 		}
1670 #endif
1671 	}
1672 }
1673 
TransformPoint(const vec3_t in,vec3_t out,mdxaBone_t * mat)1674 void TransformPoint (const vec3_t in, vec3_t out, mdxaBone_t *mat) {
1675 	for (int i=0;i<3;i++)
1676 	{
1677 		out[i]= in[0]*mat->matrix[i][0] + in[1]*mat->matrix[i][1] + in[2]*mat->matrix[i][2];
1678 	}
1679 }
1680 
TransformAndTranslatePoint(const vec3_t in,vec3_t out,mdxaBone_t * mat)1681 void TransformAndTranslatePoint (const vec3_t in, vec3_t out, mdxaBone_t *mat) {
1682 
1683 	for (int i=0;i<3;i++)
1684 	{
1685 		out[i]= in[0]*mat->matrix[i][0] + in[1]*mat->matrix[i][1] + in[2]*mat->matrix[i][2] + mat->matrix[i][3];
1686 	}
1687 }
1688 
1689 
1690 // create a matrix using a set of angles
Create_Matrix(const float * angle,mdxaBone_t * matrix)1691 void Create_Matrix(const float *angle, mdxaBone_t *matrix)
1692 {
1693 	vec3_t		axis[3];
1694 
1695 	// convert angles to axis
1696 	AnglesToAxis( angle, axis );
1697 	matrix->matrix[0][0] = axis[0][0];
1698 	matrix->matrix[1][0] = axis[0][1];
1699 	matrix->matrix[2][0] = axis[0][2];
1700 
1701 	matrix->matrix[0][1] = axis[1][0];
1702 	matrix->matrix[1][1] = axis[1][1];
1703 	matrix->matrix[2][1] = axis[1][2];
1704 
1705 	matrix->matrix[0][2] = axis[2][0];
1706 	matrix->matrix[1][2] = axis[2][1];
1707 	matrix->matrix[2][2] = axis[2][2];
1708 
1709 	matrix->matrix[0][3] = 0;
1710 	matrix->matrix[1][3] = 0;
1711 	matrix->matrix[2][3] = 0;
1712 
1713 
1714 }
1715 
1716 // given a matrix, generate the inverse of that matrix
Inverse_Matrix(mdxaBone_t * src,mdxaBone_t * dest)1717 void Inverse_Matrix(mdxaBone_t *src, mdxaBone_t *dest)
1718 {
1719 	int i, j;
1720 
1721     for (i = 0; i < 3; i++)
1722 	{
1723         for (j = 0; j < 3; j++)
1724 		{
1725             dest->matrix[i][j]=src->matrix[j][i];
1726 		}
1727 	}
1728     for (i = 0; i < 3; i++)
1729 	{
1730         dest->matrix[i][3]=0;
1731         for (j = 0; j < 3; j++)
1732 		{
1733             dest->matrix[i][3]-=dest->matrix[i][j]*src->matrix[j][3];
1734 		}
1735 	}
1736 }
1737 
1738 // generate the world matrix for a given set of angles and origin - called from lots of places
G2_GenerateWorldMatrix(const vec3_t angles,const vec3_t origin)1739 void G2_GenerateWorldMatrix(const vec3_t angles, const vec3_t origin)
1740 {
1741 	Create_Matrix(angles, &worldMatrix);
1742 	worldMatrix.matrix[0][3] = origin[0];
1743 	worldMatrix.matrix[1][3] = origin[1];
1744 	worldMatrix.matrix[2][3] = origin[2];
1745 
1746 	Inverse_Matrix(&worldMatrix, &worldMatrixInv);
1747 }
1748 
1749 // go away and determine what the pointer for a specific surface definition within the model definition is
G2_FindSurface(const model_s * mod,int index,int lod)1750 void *G2_FindSurface(const model_s *mod, int index, int lod)
1751 {
1752 	assert(mod);
1753 	assert(mod->mdxm);
1754 
1755 	// point at first lod list
1756 	byte	*current = (byte*)((intptr_t)mod->mdxm + (intptr_t)mod->mdxm->ofsLODs);
1757 	int i;
1758 
1759 	//walk the lods
1760 	assert(lod>=0&&lod<mod->mdxm->numLODs);
1761 	for (i=0; i<lod; i++)
1762 	{
1763 		mdxmLOD_t *lodData = (mdxmLOD_t *)current;
1764 		current += lodData->ofsEnd;
1765 	}
1766 
1767 	// avoid the lod pointer data structure
1768 	current += sizeof(mdxmLOD_t);
1769 
1770 	mdxmLODSurfOffset_t *indexes = (mdxmLODSurfOffset_t *)current;
1771 	// we are now looking at the offset array
1772 	assert(index>=0&&index<mod->mdxm->numSurfaces);
1773 	current += indexes->offsets[index];
1774 
1775 	return (void *)current;
1776 }
1777 
1778 
1779 #define SURFACE_SAVE_BLOCK_SIZE	sizeof(surfaceInfo_t)
1780 #define BOLT_SAVE_BLOCK_SIZE sizeof(boltInfo_t)
1781 #define BONE_SAVE_BLOCK_SIZE sizeof(boneInfo_t)
1782 
1783 
G2_SaveGhoul2Models(CGhoul2Info_v & ghoul2)1784 void G2_SaveGhoul2Models(
1785 	CGhoul2Info_v& ghoul2)
1786 {
1787 	ojk::SavedGameHelper saved_game(
1788 		::ri.saved_game);
1789 
1790 	saved_game.reset_buffer();
1791 
1792 	// is there anything to save?
1793 	if (!ghoul2.IsValid() || ghoul2.size() == 0)
1794 	{
1795 		const int zero_size = 0;
1796 
1797 #ifdef JK2_MODE
1798 		saved_game.write<int32_t>(
1799 			zero_size);
1800 
1801 		saved_game.write_chunk_and_size<int32_t>(
1802 			INT_ID('G', 'L', '2', 'S'),
1803 			INT_ID('G', 'H', 'L', '2'));
1804 #else
1805 		saved_game.write_chunk<int32_t>(
1806 			INT_ID('G', 'H', 'L', '2'),
1807 			zero_size); //write out a zero buffer
1808 #endif // JK2_MODE
1809 
1810 		return;
1811 	}
1812 
1813 
1814 	// save out how many ghoul2 models we have
1815 	const int model_count = static_cast<int>(ghoul2.size());
1816 
1817 	saved_game.write<int32_t>(
1818 		model_count);
1819 
1820 	for (int i = 0; i < model_count; ++i)
1821 	{
1822 		// first save out the ghoul2 details themselves
1823 		ghoul2[i].sg_export(
1824 			saved_game);
1825 
1826 		// save out how many surfaces we have
1827 		const int surface_count = static_cast<int>(ghoul2[i].mSlist.size());
1828 
1829 		saved_game.write<int32_t>(
1830 			surface_count);
1831 
1832 		// now save the all the surface list info
1833 		for (int x = 0; x < surface_count; ++x)
1834 		{
1835 			ghoul2[i].mSlist[x].sg_export(
1836 				saved_game);
1837 		}
1838 
1839 		// save out how many bones we have
1840 		const int bone_count = static_cast<int>(ghoul2[i].mBlist.size());
1841 
1842 		saved_game.write<int32_t>(
1843 			bone_count);
1844 
1845 		// now save the all the bone list info
1846 		for (int x = 0; x < bone_count; ++x)
1847 		{
1848 			ghoul2[i].mBlist[x].sg_export(
1849 				saved_game);
1850 		}
1851 
1852 		// save out how many bolts we have
1853 		const int bolt_count = static_cast<int>(ghoul2[i].mBltlist.size());
1854 
1855 		saved_game.write<int32_t>(
1856 			bolt_count);
1857 
1858 		// lastly save the all the bolt list info
1859 		for (int x = 0; x < bolt_count; ++x)
1860 		{
1861 			ghoul2[i].mBltlist[x].sg_export(
1862 				saved_game);
1863 		}
1864 	}
1865 
1866 #ifdef JK2_MODE
1867 	saved_game.write_chunk_and_size<int32_t>(
1868 		INT_ID('G', 'L', '2', 'S'),
1869 		INT_ID('G', 'H', 'L', '2'));
1870 #else
1871 	saved_game.write_chunk(
1872 		INT_ID('G', 'H', 'L', '2'));
1873 #endif // JK2_MODE
1874 }
1875 
1876 // FIXME Remove 'buffer' parameter
G2_LoadGhoul2Model(CGhoul2Info_v & ghoul2,char * buffer)1877 void G2_LoadGhoul2Model(
1878 	CGhoul2Info_v& ghoul2,
1879 	char* buffer)
1880 {
1881 	static_cast<void>(buffer);
1882 
1883 	ojk::SavedGameHelper saved_game(
1884 		::ri.saved_game);
1885 
1886 	// first thing, lets see how many ghoul2 models we have, and resize our buffers accordingly
1887 	int model_count = 0;
1888 
1889 #ifdef JK2_MODE
1890 	if (saved_game.get_buffer_size() > 0)
1891 	{
1892 #endif // JK2_MODE
1893 
1894 		saved_game.read<int32_t>(
1895 			model_count);
1896 
1897 #ifdef JK2_MODE
1898 	}
1899 #endif // JK2_MODE
1900 
1901 
1902 	ghoul2.resize(
1903 		model_count);
1904 
1905 	// did we actually resize to a value?
1906 	if (model_count == 0)
1907 	{
1908 		// no, ok, well, done then.
1909 		return;
1910 	}
1911 
1912 	// now we have enough instances, lets go through each one and load up the relevant details
1913 	for (decltype(model_count) i = 0; i < model_count; ++i)
1914 	{
1915 		ghoul2[i].mSkelFrameNum = 0;
1916 		ghoul2[i].mModelindex = -1;
1917 		ghoul2[i].mFileName[0] = 0;
1918 		ghoul2[i].mValid = false;
1919 
1920 		// load the ghoul2 info from the buffer
1921 		ghoul2[i].sg_import(
1922 			saved_game);
1923 
1924 		if (ghoul2[i].mModelindex != -1 && ghoul2[i].mFileName[0])
1925 		{
1926 			ghoul2[i].mModelindex = i;
1927 
1928 			::G2_SetupModelPointers(
1929 				&ghoul2[i]);
1930 		}
1931 
1932 		// give us enough surfaces to load up the data
1933 		int surface_count = 0;
1934 
1935 		saved_game.read<int32_t>(
1936 			surface_count);
1937 
1938 		ghoul2[i].mSlist.resize(surface_count);
1939 
1940 		// now load all the surfaces
1941 		for (decltype(surface_count) x = 0; x < surface_count; ++x)
1942 		{
1943 			ghoul2[i].mSlist[x].sg_import(
1944 				saved_game);
1945 		}
1946 
1947 		// give us enough bones to load up the data
1948 		int bone_count = 0;
1949 
1950 		saved_game.read<int32_t>(
1951 			bone_count);
1952 
1953 		ghoul2[i].mBlist.resize(
1954 			bone_count);
1955 
1956 		// now load all the bones
1957 		for (decltype(bone_count) x = 0; x < bone_count; ++x)
1958 		{
1959 			ghoul2[i].mBlist[x].sg_import(
1960 				saved_game);
1961 		}
1962 
1963 		// give us enough bolts to load up the data
1964 		int bolt_count = 0;
1965 
1966 		saved_game.read<int32_t>(
1967 			bolt_count);
1968 
1969 		ghoul2[i].mBltlist.resize(
1970 			bolt_count);
1971 
1972 		// now load all the bolts
1973 		for (decltype(bolt_count) x = 0; x < bolt_count; ++x)
1974 		{
1975 			ghoul2[i].mBltlist[x].sg_import(
1976 				saved_game);
1977 		}
1978 	}
1979 
1980 	saved_game.ensure_all_data_read();
1981 }
1982