//-----------------------------------------------------------------------------
// Updates the relative orientation of the camera, spring mode
//-----------------------------------------------------------------------------
void CWeaponIFMSteadyCam::UpdateDirectRelativeOrientation()
{
	// Compute a player to steadycam matrix
	VMatrix steadyCamToPlayer;
	MatrixFromAngles( m_angRelativeAngles, steadyCamToPlayer );
	MatrixSetColumn( steadyCamToPlayer, 3, m_vecRelativePosition );

	// Compute a forward direction
	Vector vecCurrentForward;
	MatrixGetColumn( steadyCamToPlayer, 0, &vecCurrentForward );

	// Before any updating occurs, sample the current 
	// world-space direction of the mouse
	Vector vecDesiredDirection;
	ComputeMouseRay( steadyCamToPlayer, vecDesiredDirection );

	// rebuild a roll-less orientation based on that direction vector
	matrix3x4_t mat;
	MatrixFromForwardDirection( vecDesiredDirection, mat );
	MatrixAngles( mat, m_angRelativeAngles );
	Assert( m_angRelativeAngles.IsValid() );

	m_vecActualViewOffset -= m_vecViewOffset;
	m_vecViewOffset.Init();
}
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
// adnan
// want to add an angles modifier key
bool CGravControllerPoint::UpdateObject( CBasePlayer *pPlayer, CBaseEntity *pEntity )
{
	IPhysicsObject *pPhysics = GetPhysObjFromPhysicsBone( pEntity, m_attachedPhysicsBone );
	if ( !pEntity || !pPhysics )
	{
		return false;
	}

#ifdef ARGG
	// adnan
	// if we've been rotating it, set it to its proper new angles (change m_attachedAnglesPlayerSpace while modifier)
	//Pickup_GetRotatedCarryAngles( pEntity, pPlayer, pPlayer->EntityToWorldTransform(), angles );
	// added the ... && (mousedx | mousedy) so we dont have to calculate if no mouse movement
	// UPDATE: m_vecRotatedCarryAngles has become a temp variable... can be cleaned up by using actual temp vars
#ifdef CLIENT_DLL
	if( m_bHasRotatedCarryAngles && (pPlayer->m_pCurrentCommand->mousedx || pPlayer->m_pCurrentCommand->mousedy) )
#else
	if( m_bHasRotatedCarryAngles && (pPlayer->GetCurrentCommand()->mousedx || pPlayer->GetCurrentCommand()->mousedy) )
#endif
	{
		// method II: relative orientation
		VMatrix vDeltaRotation, vCurrentRotation, vNewRotation;
		
		MatrixFromAngles( m_targetRotation, vCurrentRotation );

#ifdef CLIENT_DLL
		m_vecRotatedCarryAngles[YAW] = pPlayer->m_pCurrentCommand->mousedx*0.05;
		m_vecRotatedCarryAngles[PITCH] = pPlayer->m_pCurrentCommand->mousedy*-0.05;
#else
		m_vecRotatedCarryAngles[YAW] = pPlayer->GetCurrentCommand()->mousedx*0.05;
		m_vecRotatedCarryAngles[PITCH] = pPlayer->GetCurrentCommand()->mousedy*-0.05;
#endif
		m_vecRotatedCarryAngles[ROLL] = 0;
		MatrixFromAngles( m_vecRotatedCarryAngles, vDeltaRotation );

		MatrixMultiply(vDeltaRotation, vCurrentRotation, vNewRotation);
		MatrixToAngles( vNewRotation, m_targetRotation );
	}
	// end adnan
#endif

	SetTargetPosition( m_targetPosition, m_targetRotation );

	return true;
}
Example #3
0
void MatrixMultiplyRotation(matrix_t m, vec_t pitch, vec_t yaw, vec_t roll)
{
	matrix_t        tmp, rot;

	MatrixCopy(m, tmp);
	MatrixFromAngles(rot, pitch, yaw, roll);

	MatrixMultiply(rot, tmp, m);
}
//-----------------------------------------------------------------------------
// Computes the position of the canister
//-----------------------------------------------------------------------------
void CEnvHeadcrabCanisterShared::GetPositionAtTime( float flTime, Vector &vecPosition, QAngle &vecAngles )
{
	float flDeltaTime = flTime - m_flLaunchTime;
	if ( flDeltaTime > m_flFlightTime )
	{
		flDeltaTime = m_flFlightTime;
	}

	VMatrix initToWorld;
	if ( m_bLaunchedFromWithinWorld || m_bInSkybox )
	{
		VectorMA( m_vecStartPosition, flDeltaTime * m_flHorizSpeed, m_vecParabolaDirection, vecPosition );
		vecPosition.z += m_flInitialZSpeed * flDeltaTime + 0.5f * m_flZAcceleration * flDeltaTime * flDeltaTime;

		Vector vecLeft;
		CrossProduct( m_vecParabolaDirection, Vector( 0, 0, 1 ), vecLeft );

		Vector vecForward;
		VectorMultiply( m_vecParabolaDirection, -1.0f, vecForward );
		vecForward.z = -(m_flInitialZSpeed + m_flZAcceleration * flDeltaTime) / m_flHorizSpeed;	// This is -dz/dx.
		VectorNormalize( vecForward );

		Vector vecUp;
		CrossProduct( vecForward, vecLeft, vecUp );
 
		initToWorld.SetBasisVectors( vecForward, vecLeft, vecUp );
	}
	else
	{
		flDeltaTime -= m_flWorldEnterTime;
		Vector vecVelocity;
		VectorMultiply( m_vecDirection, m_flFlightSpeed, vecVelocity );
		VectorMA( m_vecEnterWorldPosition, flDeltaTime, vecVelocity, vecPosition );

		MatrixFromAngles( m_vecStartAngles.Get(), initToWorld );
	}

	VMatrix rotation;
	MatrixBuildRotationAboutAxis( rotation, Vector( 1, 0, 0 ), flDeltaTime * ROTATION_SPEED );

	VMatrix newAngles;
	MatrixMultiply( initToWorld, rotation, newAngles );
	MatrixToAngles( newAngles, vecAngles );
}
Example #5
0
//-----------------------------------------------------------------------------
// Read in worldcraft data...
//-----------------------------------------------------------------------------
bool CVGuiScreen::KeyValue( const char *szKeyName, const char *szValue ) 
{
	//!! temp hack, until worldcraft is fixed
	// strip the # tokens from (duplicate) key names
	char *s = (char *)strchr( szKeyName, '#' );
	if ( s )
	{
		*s = '\0';
	}

	if ( FStrEq( szKeyName, "panelname" ))
	{
		SetPanelName( szValue );
		return true;
	}

	// NOTE: Have to do these separate because they set two values instead of one
	if( FStrEq( szKeyName, "angles" ) )
	{
		Assert( GetMoveParent() == NULL );
		QAngle angles;
		UTIL_StringToVector( angles.Base(), szValue );

		// Because the vgui screen basis is strange (z is front, y is up, x is right)
		// we need to rotate the typical basis before applying it
		VMatrix mat, rotation, tmp;
		MatrixFromAngles( angles, mat );
		MatrixBuildRotationAboutAxis( rotation, Vector( 0, 1, 0 ), 90 );
		MatrixMultiply( mat, rotation, tmp );
		MatrixBuildRotateZ( rotation, 90 );
		MatrixMultiply( tmp, rotation, mat );
		MatrixToAngles( mat, angles );
		SetAbsAngles( angles );

		return true;
	}

	return BaseClass::KeyValue( szKeyName, szValue );
}
Example #6
0
void Draw_Scene(void (*drawFunc) (void))
{
#if defined(USE_OPENGL)
	Uint8          *keys;
	matrix_t        rotation;
	vec3_t          forward, right, up;
	qboolean        mouseGrabbed;
	qboolean		mouseGrabbedLastFrame;
	int             oldTime, newTime, deltaTime;	// for frame independent movement

	mouseGrabbed = qfalse;
	mouseGrabbedLastFrame = qfalse;

	oldTime = SDL_GetTicks();
	while(1)
	{
		SDL_Event       event;

		newTime = SDL_GetTicks();
		deltaTime = newTime - oldTime;

		//Sys_Printf(" deltaTime (%5.2f seconds)\n", (deltaTime / 1000.0));

		MatrixFromAngles(rotation, drawAngles[PITCH], drawAngles[YAW], drawAngles[ROLL]);
		MatrixToVectorsFRU(rotation, forward, right, up);

		while(SDL_PollEvent(&event))
		{
			switch (event.type)
			{
				case SDL_VIDEORESIZE:
				{
					drawScreen =
						SDL_SetVideoMode(event.resize.w, event.resize.h, drawVideo->vfmt->BitsPerPixel,
										 SDL_OPENGL | SDL_RESIZABLE);
					if(drawScreen)
					{
						Reshape(drawScreen->w, drawScreen->h);
					}
					else
					{
						/* Uh oh, we couldn't set the new video mode?? */ ;
					}
					break;
				}

				case SDL_MOUSEMOTION:
				{
					if(mouseGrabbed && !mouseGrabbedLastFrame)
					{
						drawAngles[PITCH] += event.motion.yrel;
						drawAngles[YAW] -= event.motion.xrel;
					}
					mouseGrabbedLastFrame = qfalse;
					break;
				}

				case SDL_MOUSEBUTTONDOWN:
				{
					switch (event.button.button)
					{
						case 3:
						{		// K_MOUSE2;
							if(!mouseGrabbed)
							{
								SDL_WM_GrabInput(SDL_GRAB_ON);
								SDL_ShowCursor(0);
								mouseGrabbed = qtrue;
								mouseGrabbedLastFrame = qtrue;
							}
							else
							{
								SDL_ShowCursor(1);
								SDL_WM_GrabInput(SDL_GRAB_OFF);
								mouseGrabbed = qfalse;
							}
							break;
						}

						default:
							break;
					}
					break;
				}

				case SDL_QUIT:
				{
					Draw_Shutdown();
					return;
				}

				default:
					break;
			}
		}


		keys = SDL_GetKeyState(NULL);

		if(keys[SDLK_ESCAPE])
		{
			Draw_Shutdown();
			return;
		}

		if(keys[SDLK_w])
		{
			if(SDL_GetModState() & KMOD_SHIFT)
			{
				VectorMA(drawOrigin, 0.5 * deltaTime, forward, drawOrigin);
			}
			else
			{
				VectorMA(drawOrigin, 1.0 * deltaTime, forward, drawOrigin);
			}
		}

		if(keys[SDLK_s])
		{
			if(SDL_GetModState() & KMOD_SHIFT)
			{
				VectorMA(drawOrigin, -0.5 * deltaTime, forward, drawOrigin);
			}
			else
			{
				VectorMA(drawOrigin, -1.0 * deltaTime, forward, drawOrigin);
			}
		}

		if(keys[SDLK_a])
		{
			if(SDL_GetModState() & KMOD_SHIFT)
			{
				VectorMA(drawOrigin, -0.5 * deltaTime, right, drawOrigin);
			}
			else
			{
				VectorMA(drawOrigin, -1.0 * deltaTime, right, drawOrigin);
			}
		}

		if(keys[SDLK_d])
		{
			if(SDL_GetModState() & KMOD_SHIFT)
			{
				VectorMA(drawOrigin, 0.5 * deltaTime, right, drawOrigin);
			}
			else
			{
				VectorMA(drawOrigin, 1.0 * deltaTime, right, drawOrigin);
			}
		}

		if(keys[SDLK_SPACE])
		{
			//drawOrigin[2] += 1.0 * deltaTime;
			if(SDL_GetModState() & KMOD_SHIFT)
			{
				VectorMA(drawOrigin, 0.5 * deltaTime, up, drawOrigin);
			}
			else
			{
				VectorMA(drawOrigin, 1.0 * deltaTime, up, drawOrigin);
			}
		}

		if(keys[SDLK_c])
		{
			//drawOrigin[2] -= 1.0 * deltaTime;
			if(SDL_GetModState() & KMOD_SHIFT)
			{
				VectorMA(drawOrigin, -0.5 * deltaTime, up, drawOrigin);
			}
			else
			{
				VectorMA(drawOrigin, -1.0 * deltaTime, up, drawOrigin);
			}
		}

		if(keys[SDLK_UP])
		{
			drawAngles[PITCH] -= 1.0 * deltaTime;
		}

		if(keys[SDLK_DOWN])
		{
			drawAngles[PITCH] += 1.0 * deltaTime;
		}

		if(keys[SDLK_LEFT])
		{
			drawAngles[YAW] += 1.0 * deltaTime;
		}

		if(keys[SDLK_RIGHT])
		{
			drawAngles[YAW] -= 1.0 * deltaTime;
		}

		// check to make sure the angles haven't wrapped
		if(drawAngles[PITCH] < -90)
		{
			drawAngles[PITCH] = -90;
		}
		else if(drawAngles[PITCH] > 90)
		{
			drawAngles[PITCH] = 90;
		}

		Draw_BeginScene();
		drawFunc();
		Draw_EndScene();

		oldTime = newTime;
	}
#endif // #if defined(USE_OPENGL)
}
Example #7
0
VMatrix SetupMatrixAngles(const QAngle &vAngles)
{
	VMatrix mRet;
	MatrixFromAngles( vAngles, mRet );
	return mRet;
}
void CWeaponIFMSteadyCam::UpdateRelativeOrientation()
{
	if ( m_bIsLocked )
		return;

	if ( m_bInDirectMode )
	{
		UpdateDirectRelativeOrientation();
		return;
	}

	if ( ( m_vecViewOffset.x == 0.0f ) && ( m_vecViewOffset.y == 0.0f ) )
		return;

	// Compute a player to steadycam matrix
	VMatrix steadyCamToPlayer;
	MatrixFromAngles( m_angRelativeAngles, steadyCamToPlayer );
	MatrixSetColumn( steadyCamToPlayer, 3, m_vecRelativePosition );

	Vector vecCurrentForward;
	MatrixGetColumn( steadyCamToPlayer, 0, &vecCurrentForward );

	// Create a ray in steadycam space
	float flMaxD = 1.0f / tan( M_PI * m_flFOV / 360.0f );

	// Remap offsets into normalized space
	float flViewX = m_vecViewOffset.x / ( 384 / 2 );
	float flViewY = m_vecViewOffset.y / ( 288 / 2 );

	flViewX *= flMaxD * ifm_steadycam_mousefactor.GetFloat();
	flViewY *= flMaxD * ifm_steadycam_mousefactor.GetFloat();
				    
	Vector vecSelectionDir( 1.0f, -flViewX, -flViewY );
	VectorNormalize( vecSelectionDir );

	// Rotate the ray into player coordinates
	Vector vecDesiredDirection;
	Vector3DMultiply( steadyCamToPlayer, vecSelectionDir, vecDesiredDirection );

	float flDot = DotProduct( vecDesiredDirection, vecCurrentForward );
	flDot = clamp( flDot, -1.0f, 1.0f );
	float flAngle = 180.0f * acos( flDot ) / M_PI;
	if ( flAngle < 1e-3 )
	{
		matrix3x4_t mat;
		MatrixFromForwardDirection( vecDesiredDirection, mat );
		MatrixAngles( mat, m_angRelativeAngles );
		return;
	}

	Vector vecAxis;
	CrossProduct( vecCurrentForward, vecDesiredDirection, vecAxis );
	VectorNormalize( vecAxis );
	
	float flRotateRate = ifm_steadycam_rotaterate.GetFloat();
	if ( flRotateRate < 1.0f )
	{
		flRotateRate = 1.0f;
	}

	float flRateFactor = flAngle / flRotateRate;
	flRateFactor *= flRateFactor * flRateFactor;
	float flRate = flRateFactor * 30.0f;
	float flMaxAngle = gpGlobals->frametime * flRate;
	flAngle = clamp( flAngle, 0.0f, flMaxAngle );

	Vector vecNewForard;
	VMatrix rotation;
	MatrixBuildRotationAboutAxis( rotation, vecAxis, flAngle ); 
	Vector3DMultiply( rotation, vecCurrentForward, vecNewForard );

	matrix3x4_t mat;
	MatrixFromForwardDirection( vecNewForard, mat );
	MatrixAngles( mat, m_angRelativeAngles );

	Assert( m_angRelativeAngles.IsValid() );
}
Example #9
0
static void PopulateTraceNodes(void)
{
	int             i, m, frame, castShadows;
	float           temp;
	entity_t       *e;
	const char     *value;
	picoModel_t    *model;
	vec3_t          origin, scale, angles;
	matrix_t        rotation;
	matrix_t        transform;


	/* add worldspawn triangles */
	MatrixIdentity(transform);
	PopulateWithBSPModel(&bspModels[0], transform);

	/* walk each entity list */
	for(i = 1; i < numEntities; i++)
	{
		/* get entity */
		e = &entities[i];

		/* get shadow flags */
		castShadows = ENTITY_CAST_SHADOWS;
		GetEntityShadowFlags(e, NULL, &castShadows, NULL);

		/* early out? */
		if(!castShadows)
			continue;

		/* get entity origin */
		GetVectorForKey(e, "origin", origin);

		/* get "angle" (yaw) or "angles" (pitch yaw roll) */
		MatrixIdentity(rotation);
		angles[0] = angles[1] = angles[2] = 0.0f;

		value = ValueForKey(e, "angle");
		if(value[0] != '\0')
		{
			angles[1] = atof(value);
			MatrixFromAngles(rotation, angles[PITCH], angles[YAW], angles[ROLL]);
		}

		value = ValueForKey(e, "angles");
		if(value[0] != '\0')
		{
			sscanf(value, "%f %f %f", &angles[0], &angles[1], &angles[2]);
			MatrixFromAngles(rotation, angles[PITCH], angles[YAW], angles[ROLL]);
		}

		value = ValueForKey(e, "rotation");
		if(value[0] != '\0')
		{
			sscanf(value, "%f %f %f %f %f %f %f %f %f", &rotation[0], &rotation[1], &rotation[2],
				   &rotation[4], &rotation[5], &rotation[6], &rotation[8], &rotation[9], &rotation[10]);
		}

		/* get scale */
		scale[0] = scale[1] = scale[2] = 1.0f;
		temp = FloatForKey(e, "modelscale");
		if(temp != 0.0f)
			scale[0] = scale[1] = scale[2] = temp;
		value = ValueForKey(e, "modelscale_vec");
		if(value[0] != '\0')
			sscanf(value, "%f %f %f", &scale[0], &scale[1], &scale[2]);

		MatrixMultiplyScale(rotation, scale[0], scale[1], scale[2]);

		/* set transform matrix */
		MatrixIdentity(transform);
		MatrixSetupTransformFromRotation(transform, rotation, origin);

		//% m4x4_pivoted_transform_by_vec3(transform, origin, angles, eXYZ, scale, vec3_origin);

		/* get model */
		value = ValueForKey(e, "model");

		/* switch on model type */
		switch (value[0])
		{
				/* no model */
			case '\0':
				break;

				/* bsp model */
			case '*':
				m = atoi(&value[1]);
				if(m <= 0 || m >= numBSPModels)
					continue;
				PopulateWithBSPModel(&bspModels[m], transform);
				break;

				/* external model */
			default:
				frame = IntForKey(e, "_frame");
				model = LoadModel((char *)value, frame);
				if(model == NULL)
					continue;
				PopulateWithPicoModel(castShadows, model, transform);
				continue;
		}

		/* get model2 */
		value = ValueForKey(e, "model2");

		/* switch on model type */
		switch (value[0])
		{
				/* no model */
			case '\0':
				break;

				/* bsp model */
			case '*':
				m = atoi(&value[1]);
				if(m <= 0 || m >= numBSPModels)
					continue;
				PopulateWithBSPModel(&bspModels[m], transform);
				break;

				/* external model */
			default:
				frame = IntForKey(e, "_frame2");
				model = LoadModel((char *)value, frame);
				if(model == NULL)
					continue;
				PopulateWithPicoModel(castShadows, model, transform);
				continue;
		}
	}
}
Example #10
0
/*
=================
R_LoadPSK
=================
*/
qboolean R_LoadPSK( model_t *mod, void *buffer, int bufferSize, const char *modName )
{
	int               i, j, k;
	memStream_t       *stream = NULL;

	axChunkHeader_t   chunkHeader;

	int               numPoints;
	axPoint_t         *point;
	axPoint_t         *points = NULL;

	int               numVertexes;
	axVertex_t        *vertex;
	axVertex_t        *vertexes = NULL;

	//int       numSmoothGroups;
	int               numTriangles;
	axTriangle_t      *triangle;
	axTriangle_t      *triangles = NULL;

	int               numMaterials;
	axMaterial_t      *material;
	axMaterial_t      *materials = NULL;

	int               numReferenceBones;
	axReferenceBone_t *refBone;
	axReferenceBone_t *refBones = NULL;

	int               numWeights;
	axBoneWeight_t    *axWeight;
	axBoneWeight_t    *axWeights = NULL;

	md5Model_t        *md5;
	md5Bone_t         *md5Bone;

	vec3_t            boneOrigin;
	quat_t            boneQuat;
	//matrix_t        boneMat;

	int               materialIndex, oldMaterialIndex;

	int               numRemaining;

	growList_t        sortedTriangles;
	growList_t        vboVertexes;
	growList_t        vboTriangles;
	growList_t        vboSurfaces;

	int               numBoneReferences;
	int               boneReferences[ MAX_BONES ];

	matrix_t          unrealToQuake;

#define DeallocAll() Com_Dealloc( materials ); \
	Com_Dealloc( points ); \
	Com_Dealloc( vertexes ); \
	Com_Dealloc( triangles ); \
	Com_Dealloc( refBones ); \
	Com_Dealloc( axWeights ); \
	FreeMemStream( stream );

	//MatrixSetupScale(unrealToQuake, 1, -1, 1);
	MatrixFromAngles( unrealToQuake, 0, 90, 0 );

	stream = AllocMemStream( (byte*) buffer, bufferSize );
	GetChunkHeader( stream, &chunkHeader );

	// check indent again
	if ( Q_strnicmp( chunkHeader.ident, "ACTRHEAD", 8 ) )
	{
		ri.Printf( PRINT_WARNING, "R_LoadPSK: '%s' has wrong chunk indent ('%s' should be '%s')\n", modName, chunkHeader.ident, "ACTRHEAD" );
		DeallocAll();
		return qfalse;
	}

	PrintChunkHeader( &chunkHeader );

	mod->type = MOD_MD5;
	mod->dataSize += sizeof( md5Model_t );
	md5 = mod->md5 = (md5Model_t*) ri.Hunk_Alloc( sizeof( md5Model_t ), h_low );

	// read points
	GetChunkHeader( stream, &chunkHeader );

	if ( Q_strnicmp( chunkHeader.ident, "PNTS0000", 8 ) )
	{
		ri.Printf( PRINT_WARNING, "R_LoadPSK: '%s' has wrong chunk indent ('%s' should be '%s')\n", modName, chunkHeader.ident, "PNTS0000" );
		DeallocAll();
		return qfalse;
	}

	if ( chunkHeader.dataSize != sizeof( axPoint_t ) )
	{
		ri.Printf( PRINT_WARNING, "R_LoadPSK: '%s' has wrong chunk dataSize ('%i' should be '%i')\n", modName, chunkHeader.dataSize, ( int ) sizeof( axPoint_t ) );
		DeallocAll();
		return qfalse;
	}

	PrintChunkHeader( &chunkHeader );

	numPoints = chunkHeader.numData;
	points = (axPoint_t*) Com_Allocate( numPoints * sizeof( axPoint_t ) );

	for ( i = 0, point = points; i < numPoints; i++, point++ )
	{
		point->point[ 0 ] = MemStreamGetFloat( stream );
		point->point[ 1 ] = MemStreamGetFloat( stream );
		point->point[ 2 ] = MemStreamGetFloat( stream );

#if 0
		// Tr3B: HACK convert from Unreal coordinate system to the Quake one
		MatrixTransformPoint2( unrealToQuake, point->point );
#endif
	}

	// read vertices
	GetChunkHeader( stream, &chunkHeader );

	if ( Q_strnicmp( chunkHeader.ident, "VTXW0000", 8 ) )
	{
		ri.Printf( PRINT_WARNING, "R_LoadPSK: '%s' has wrong chunk indent ('%s' should be '%s')\n", modName, chunkHeader.ident, "VTXW0000" );
		DeallocAll();
		return qfalse;
	}

	if ( chunkHeader.dataSize != sizeof( axVertex_t ) )
	{
		ri.Printf( PRINT_WARNING, "R_LoadPSK: '%s' has wrong chunk dataSize ('%i' should be '%i')\n", modName, chunkHeader.dataSize, ( int ) sizeof( axVertex_t ) );
		DeallocAll();
		return qfalse;
	}

	PrintChunkHeader( &chunkHeader );

	numVertexes = chunkHeader.numData;
	vertexes = (axVertex_t*) Com_Allocate( numVertexes * sizeof( axVertex_t ) );

	for ( i = 0, vertex = vertexes; i < numVertexes; i++, vertex++ )
	{
		vertex->pointIndex = MemStreamGetShort( stream );

		if ( vertex->pointIndex < 0 || vertex->pointIndex >= numPoints )
		{
			ri.Printf( PRINT_WARNING, "R_LoadPSK: '%s' has vertex with point index out of range (%i while max %i)\n", modName, vertex->pointIndex, numPoints );
			DeallocAll();
			return qfalse;
		}

		vertex->unknownA = MemStreamGetShort( stream );
		vertex->st[ 0 ] = MemStreamGetFloat( stream );
		vertex->st[ 1 ] = MemStreamGetFloat( stream );
		vertex->materialIndex = MemStreamGetC( stream );
		vertex->reserved = MemStreamGetC( stream );
		vertex->unknownB = MemStreamGetShort( stream );

#if 0
		ri.Printf( PRINT_ALL, "R_LoadPSK: axVertex_t(%i):\n"
		           "axVertex:pointIndex: %i\n"
		           "axVertex:unknownA: %i\n"
		           "axVertex::st: %f %f\n"
		           "axVertex:materialIndex: %i\n"
		           "axVertex:reserved: %d\n"
		           "axVertex:unknownB: %d\n",
		           i,
		           vertex->pointIndex,
		           vertex->unknownA,
		           vertex->st[ 0 ], vertex->st[ 1 ],
		           vertex->materialIndex,
		           vertex->reserved,
		           vertex->unknownB );
#endif
	}

	// read triangles
	GetChunkHeader( stream, &chunkHeader );

	if ( Q_strnicmp( chunkHeader.ident, "FACE0000", 8 ) )
	{
		ri.Printf( PRINT_WARNING, "R_LoadPSK: '%s' has wrong chunk indent ('%s' should be '%s')\n", modName, chunkHeader.ident, "FACE0000" );
		DeallocAll();
		return qfalse;
	}

	if ( chunkHeader.dataSize != sizeof( axTriangle_t ) )
	{
		ri.Printf( PRINT_WARNING, "R_LoadPSK: '%s' has wrong chunk dataSize ('%i' should be '%i')\n", modName, chunkHeader.dataSize, ( int ) sizeof( axTriangle_t ) );
		DeallocAll();
		return qfalse;
	}

	PrintChunkHeader( &chunkHeader );

	numTriangles = chunkHeader.numData;
	triangles = (axTriangle_t*) Com_Allocate( numTriangles * sizeof( axTriangle_t ) );

	for ( i = 0, triangle = triangles; i < numTriangles; i++, triangle++ )
	{
		for ( j = 0; j < 3; j++ )
			//for(j = 2; j >= 0; j--)
		{
			triangle->indexes[ j ] = MemStreamGetShort( stream );

			if ( triangle->indexes[ j ] >= numVertexes )
			{
				ri.Printf( PRINT_WARNING, "R_LoadPSK: '%s' has triangle with vertex index out of range (%i while max %i)\n", modName, triangle->indexes[ j ], numVertexes );
				DeallocAll();
				return qfalse;
			}
		}

		triangle->materialIndex = MemStreamGetC( stream );
		triangle->materialIndex2 = MemStreamGetC( stream );
		triangle->smoothingGroups = MemStreamGetLong( stream );
	}

	// read materials
	GetChunkHeader( stream, &chunkHeader );

	if ( Q_strnicmp( chunkHeader.ident, "MATT0000", 8 ) )
	{
		ri.Printf( PRINT_WARNING, "R_LoadPSK: '%s' has wrong chunk indent ('%s' should be '%s')\n", modName, chunkHeader.ident, "MATT0000" );
		DeallocAll();
		return qfalse;
	}

	if ( chunkHeader.dataSize != sizeof( axMaterial_t ) )
	{
		ri.Printf( PRINT_WARNING, "R_LoadPSK: '%s' has wrong chunk dataSize ('%i' should be '%i')\n", modName, chunkHeader.dataSize, ( int ) sizeof( axMaterial_t ) );
		DeallocAll();
		return qfalse;
	}

	PrintChunkHeader( &chunkHeader );

	numMaterials = chunkHeader.numData;
	materials = (axMaterial_t*) Com_Allocate( numMaterials * sizeof( axMaterial_t ) );

	for ( i = 0, material = materials; i < numMaterials; i++, material++ )
	{
		MemStreamRead( stream, material->name, sizeof( material->name ) );

		ri.Printf( PRINT_ALL, "R_LoadPSK: material name: '%s'\n", material->name );

		material->shaderIndex = MemStreamGetLong( stream );
		material->polyFlags = MemStreamGetLong( stream );
		material->auxMaterial = MemStreamGetLong( stream );
		material->auxFlags = MemStreamGetLong( stream );
		material->lodBias = MemStreamGetLong( stream );
		material->lodStyle = MemStreamGetLong( stream );
	}

	for ( i = 0, vertex = vertexes; i < numVertexes; i++, vertex++ )
	{
		if ( vertex->materialIndex < 0 || vertex->materialIndex >= numMaterials )
		{
			ri.Printf( PRINT_WARNING, "R_LoadPSK: '%s' has vertex with material index out of range (%i while max %i)\n", modName, vertex->materialIndex, numMaterials );
			DeallocAll();
			return qfalse;
		}
	}

	for ( i = 0, triangle = triangles; i < numTriangles; i++, triangle++ )
	{
		if ( triangle->materialIndex < 0 || triangle->materialIndex >= numMaterials )
		{
			ri.Printf( PRINT_WARNING, "R_LoadPSK: '%s' has triangle with material index out of range (%i while max %i)\n", modName, triangle->materialIndex, numMaterials );
			DeallocAll();
			return qfalse;
		}
	}

	// read reference bones
	GetChunkHeader( stream, &chunkHeader );

	if ( Q_strnicmp( chunkHeader.ident, "REFSKELT", 8 ) )
	{
		ri.Printf( PRINT_WARNING, "R_LoadPSK: '%s' has wrong chunk indent ('%s' should be '%s')\n", modName, chunkHeader.ident, "REFSKELT" );
		DeallocAll();
		return qfalse;
	}

	if ( chunkHeader.dataSize != sizeof( axReferenceBone_t ) )
	{
		ri.Printf( PRINT_WARNING, "R_LoadPSK: '%s' has wrong chunk dataSize ('%i' should be '%i')\n", modName, chunkHeader.dataSize, ( int ) sizeof( axReferenceBone_t ) );
		DeallocAll();
		return qfalse;
	}

	PrintChunkHeader( &chunkHeader );

	numReferenceBones = chunkHeader.numData;
	refBones = (axReferenceBone_t*) Com_Allocate( numReferenceBones * sizeof( axReferenceBone_t ) );

	for ( i = 0, refBone = refBones; i < numReferenceBones; i++, refBone++ )
	{
		MemStreamRead( stream, refBone->name, sizeof( refBone->name ) );

		//ri.Printf(PRINT_ALL, "R_LoadPSK: reference bone name: '%s'\n", refBone->name);

		refBone->flags = MemStreamGetLong( stream );
		refBone->numChildren = MemStreamGetLong( stream );
		refBone->parentIndex = MemStreamGetLong( stream );

		GetBone( stream, &refBone->bone );

#if 0
		ri.Printf( PRINT_ALL, "R_LoadPSK: axReferenceBone_t(%i):\n"
		           "axReferenceBone_t::name: '%s'\n"
		           "axReferenceBone_t::flags: %i\n"
		           "axReferenceBone_t::numChildren %i\n"
		           "axReferenceBone_t::parentIndex: %i\n"
		           "axReferenceBone_t::quat: %f %f %f %f\n"
		           "axReferenceBone_t::position: %f %f %f\n"
		           "axReferenceBone_t::length: %f\n"
		           "axReferenceBone_t::xSize: %f\n"
		           "axReferenceBone_t::ySize: %f\n"
		           "axReferenceBone_t::zSize: %f\n",
		           i,
		           refBone->name,
		           refBone->flags,
		           refBone->numChildren,
		           refBone->parentIndex,
		           refBone->bone.quat[ 0 ], refBone->bone.quat[ 1 ], refBone->bone.quat[ 2 ], refBone->bone.quat[ 3 ],
		           refBone->bone.position[ 0 ], refBone->bone.position[ 1 ], refBone->bone.position[ 2 ],
		           refBone->bone.length,
		           refBone->bone.xSize,
		           refBone->bone.ySize,
		           refBone->bone.zSize );
#endif
	}

	// read  bone weights
	GetChunkHeader( stream, &chunkHeader );

	if ( Q_strnicmp( chunkHeader.ident, "RAWWEIGHTS", 10 ) )
	{
		ri.Printf( PRINT_WARNING, "R_LoadPSK: '%s' has wrong chunk indent ('%s' should be '%s')\n", modName, chunkHeader.ident, "RAWWEIGHTS" );
		DeallocAll();
		return qfalse;
	}

	if ( chunkHeader.dataSize != sizeof( axBoneWeight_t ) )
	{
		ri.Printf( PRINT_WARNING, "R_LoadPSK: '%s' has wrong chunk dataSize ('%i' should be '%i')\n", modName, chunkHeader.dataSize, ( int ) sizeof( axBoneWeight_t ) );
		DeallocAll();
		return qfalse;
	}

	PrintChunkHeader( &chunkHeader );

	numWeights = chunkHeader.numData;
	axWeights = (axBoneWeight_t*) Com_Allocate( numWeights * sizeof( axBoneWeight_t ) );

	for ( i = 0, axWeight = axWeights; i < numWeights; i++, axWeight++ )
	{
		axWeight->weight = MemStreamGetFloat( stream );
		axWeight->pointIndex = MemStreamGetLong( stream );
		axWeight->boneIndex = MemStreamGetLong( stream );

#if 0
		ri.Printf( PRINT_ALL, "R_LoadPSK: axBoneWeight_t(%i):\n"
		           "axBoneWeight_t::weight: %f\n"
		           "axBoneWeight_t::pointIndex %i\n"
		           "axBoneWeight_t::boneIndex: %i\n",
		           i,
		           axWeight->weight,
		           axWeight->pointIndex,
		           axWeight->boneIndex );
#endif
	}

	//
	// convert the model to an internal MD5 representation
	//
	md5->numBones = numReferenceBones;

	// calc numMeshes <number>

	/*
	numSmoothGroups = 0;
	for(i = 0, triangle = triangles; i < numTriangles; i++, triangle++)
	{
	        if(triangle->smoothingGroups)
	        {

	        }
	}
	*/

	if ( md5->numBones < 1 )
	{
		ri.Printf( PRINT_WARNING, "R_LoadPSK: '%s' has no bones\n", modName );
		DeallocAll();
		return qfalse;
	}

	if ( md5->numBones > MAX_BONES )
	{
		ri.Printf( PRINT_WARNING, "R_LoadPSK: '%s' has more than %i bones (%i)\n", modName, MAX_BONES, md5->numBones );
		DeallocAll();
		return qfalse;
	}

	//ri.Printf(PRINT_ALL, "R_LoadPSK: '%s' has %i bones\n", modName, md5->numBones);

	// copy all reference bones
	md5->bones = (md5Bone_t*) ri.Hunk_Alloc( sizeof( *md5Bone ) * md5->numBones, h_low );

	for ( i = 0, md5Bone = md5->bones, refBone = refBones; i < md5->numBones; i++, md5Bone++, refBone++ )
	{
		Q_strncpyz( md5Bone->name, refBone->name, sizeof( md5Bone->name ) );

		if ( i == 0 )
		{
			md5Bone->parentIndex = refBone->parentIndex - 1;
		}
		else
		{
			md5Bone->parentIndex = refBone->parentIndex;
		}

		//ri.Printf(PRINT_ALL, "R_LoadPSK: '%s' has bone '%s' with parent index %i\n", modName, md5Bone->name, md5Bone->parentIndex);

		if ( md5Bone->parentIndex >= md5->numBones )
		{
			DeallocAll();
			ri.Error( ERR_DROP, "R_LoadPSK: '%s' has bone '%s' with bad parent index %i while numBones is %i", modName,
			          md5Bone->name, md5Bone->parentIndex, md5->numBones );
		}

		for ( j = 0; j < 3; j++ )
		{
			boneOrigin[ j ] = refBone->bone.position[ j ];
		}

		// Tr3B: I have really no idea why the .psk format stores the first quaternion with inverted quats.
		// Furthermore only the X and Z components of the first quat are inverted ?!?!
		if ( i == 0 )
		{
			boneQuat[ 0 ] = refBone->bone.quat[ 0 ];
			boneQuat[ 1 ] = -refBone->bone.quat[ 1 ];
			boneQuat[ 2 ] = refBone->bone.quat[ 2 ];
			boneQuat[ 3 ] = refBone->bone.quat[ 3 ];
		}
		else
		{
			boneQuat[ 0 ] = -refBone->bone.quat[ 0 ];
			boneQuat[ 1 ] = -refBone->bone.quat[ 1 ];
			boneQuat[ 2 ] = -refBone->bone.quat[ 2 ];
			boneQuat[ 3 ] = refBone->bone.quat[ 3 ];
		}

		VectorCopy( boneOrigin, md5Bone->origin );
		//MatrixTransformPoint(unrealToQuake, boneOrigin, md5Bone->origin);

		QuatCopy( boneQuat, md5Bone->rotation );

		//QuatClear(md5Bone->rotation);

#if 0
		ri.Printf( PRINT_ALL, "R_LoadPSK: md5Bone_t(%i):\n"
		           "md5Bone_t::name: '%s'\n"
		           "md5Bone_t::parentIndex: %i\n"
		           "md5Bone_t::quat: %f %f %f %f\n"
		           "md5bone_t::position: %f %f %f\n",
		           i,
		           md5Bone->name,
		           md5Bone->parentIndex,
		           md5Bone->rotation[ 0 ], md5Bone->rotation[ 1 ], md5Bone->rotation[ 2 ], md5Bone->rotation[ 3 ],
		           md5Bone->origin[ 0 ], md5Bone->origin[ 1 ], md5Bone->origin[ 2 ] );
#endif

		if ( md5Bone->parentIndex >= 0 )
		{
			vec3_t    rotated;
			quat_t    quat;

			md5Bone_t *parent;

			parent = &md5->bones[ md5Bone->parentIndex ];

			QuatTransformVector( parent->rotation, md5Bone->origin, rotated );
			//QuatTransformVector(md5Bone->rotation, md5Bone->origin, rotated);

			VectorAdd( parent->origin, rotated, md5Bone->origin );

			QuatMultiply1( parent->rotation, md5Bone->rotation, quat );
			QuatCopy( quat, md5Bone->rotation );
		}

#if 0
		ri.Printf( PRINT_ALL, "R_LoadPSK: md5Bone_t(%i):\n"
		           "md5Bone_t::name: '%s'\n"
		           "md5Bone_t::parentIndex: %i\n"
		           "md5Bone_t::quat: %f %f %f %f\n"
		           "md5bone_t::position: %f %f %f\n",
		           i,
		           md5Bone->name,
		           md5Bone->parentIndex,
		           md5Bone->rotation[ 0 ], md5Bone->rotation[ 1 ], md5Bone->rotation[ 2 ], md5Bone->rotation[ 3 ],
		           md5Bone->origin[ 0 ], md5Bone->origin[ 1 ], md5Bone->origin[ 2 ] );
#endif
	}

	Com_InitGrowList( &vboVertexes, 10000 );

	for ( i = 0, vertex = vertexes; i < numVertexes; i++, vertex++ )
	{
		md5Vertex_t *vboVert = (md5Vertex_t*) Com_Allocate( sizeof( *vboVert ) );

		for ( j = 0; j < 3; j++ )
		{
			vboVert->position[ j ] = points[ vertex->pointIndex ].point[ j ];
		}

		vboVert->texCoords[ 0 ] = vertex->st[ 0 ];
		vboVert->texCoords[ 1 ] = vertex->st[ 1 ];

		// find number of associated weights
		vboVert->numWeights = 0;

		for ( j = 0, axWeight = axWeights; j < numWeights; j++, axWeight++ )
		{
			if ( axWeight->pointIndex == vertex->pointIndex && axWeight->weight > 0.0f )
			{
				vboVert->numWeights++;
			}
		}

		if ( vboVert->numWeights > MAX_WEIGHTS )
		{
			DeallocAll();
			ri.Error( ERR_DROP, "R_LoadPSK: vertex %i requires more weights %i than the maximum of %i in model '%s'", i, vboVert->numWeights, MAX_WEIGHTS, modName );
			//ri.Printf(PRINT_WARNING, "R_LoadPSK: vertex %i requires more weights %i than the maximum of %i in model '%s'\n", i, vboVert->numWeights, MAX_WEIGHTS, modName);
		}

		for ( j = 0, axWeight = axWeights, k = 0; j < numWeights; j++, axWeight++ )
		{
			if ( axWeight->pointIndex == vertex->pointIndex && axWeight->weight > 0.0f )
			{
				vboVert->boneIndexes[ k ] = axWeight->boneIndex;
				vboVert->boneWeights[ k ] = axWeight->weight;
				k++;
			}
		}

		Com_AddToGrowList( &vboVertexes, vboVert );
	}

	ClearBounds( md5->bounds[ 0 ], md5->bounds[ 1 ] );

	for ( i = 0, vertex = vertexes; i < numVertexes; i++, vertex++ )
	{
		AddPointToBounds( points[ vertex->pointIndex ].point, md5->bounds[ 0 ], md5->bounds[ 1 ] );
	}

#if 0
	ri.Printf( PRINT_ALL, "R_LoadPSK: AABB (%i %i %i) (%i %i %i)\n",
	           ( int ) md5->bounds[ 0 ][ 0 ],
	           ( int ) md5->bounds[ 0 ][ 1 ],
	           ( int ) md5->bounds[ 0 ][ 2 ],
	           ( int ) md5->bounds[ 1 ][ 0 ],
	           ( int ) md5->bounds[ 1 ][ 1 ],
	           ( int ) md5->bounds[ 1 ][ 2 ] );
#endif

	// sort triangles
	qsort( triangles, numTriangles, sizeof( axTriangle_t ), CompareTrianglesByMaterialIndex );

	Com_InitGrowList( &sortedTriangles, 1000 );

	for ( i = 0, triangle = triangles; i < numTriangles; i++, triangle++ )
	{
		skelTriangle_t *sortTri = (skelTriangle_t*) Com_Allocate( sizeof( *sortTri ) );

		for ( j = 0; j < 3; j++ )
		{
			sortTri->indexes[ j ] = triangle->indexes[ j ];
			sortTri->vertexes[ j ] = (md5Vertex_t*) Com_GrowListElement( &vboVertexes, triangle->indexes[ j ] );
		}

		sortTri->referenced = qfalse;

		Com_AddToGrowList( &sortedTriangles, sortTri );
	}

	// calc tangent spaces
#if 1
	{
		md5Vertex_t *v0, *v1, *v2;
		const float *p0, *p1, *p2;
		const float *t0, *t1, *t2;
		vec3_t      tangent;
		vec3_t      binormal;
		vec3_t      normal;

		for ( j = 0; j < vboVertexes.currentElements; j++ )
		{
			v0 = (md5Vertex_t*) Com_GrowListElement( &vboVertexes, j );

			VectorClear( v0->tangent );
			VectorClear( v0->binormal );
			VectorClear( v0->normal );
		}

		for ( j = 0; j < sortedTriangles.currentElements; j++ )
		{
			skelTriangle_t *tri = (skelTriangle_t*) Com_GrowListElement( &sortedTriangles, j );

			v0 = (md5Vertex_t*) Com_GrowListElement( &vboVertexes, tri->indexes[ 0 ] );
			v1 = (md5Vertex_t*) Com_GrowListElement( &vboVertexes, tri->indexes[ 1 ] );
			v2 = (md5Vertex_t*) Com_GrowListElement( &vboVertexes, tri->indexes[ 2 ] );

			p0 = v0->position;
			p1 = v1->position;
			p2 = v2->position;

			t0 = v0->texCoords;
			t1 = v1->texCoords;
			t2 = v2->texCoords;

#if 1
			R_CalcTangentSpace( tangent, binormal, normal, p0, p1, p2, t0, t1, t2 );
#else
			R_CalcNormalForTriangle( normal, p0, p1, p2 );
			R_CalcTangentsForTriangle( tangent, binormal, p0, p1, p2, t0, t1, t2 );
#endif

			for ( k = 0; k < 3; k++ )
			{
				float *v;

				v0 = (md5Vertex_t*) Com_GrowListElement( &vboVertexes, tri->indexes[ k ] );

				v = v0->tangent;
				VectorAdd( v, tangent, v );

				v = v0->binormal;
				VectorAdd( v, binormal, v );

				v = v0->normal;
				VectorAdd( v, normal, v );
			}
		}

		for ( j = 0; j < vboVertexes.currentElements; j++ )
		{
			v0 = (md5Vertex_t*) Com_GrowListElement( &vboVertexes, j );

			VectorNormalize( v0->tangent );
			VectorNormalize( v0->binormal );
			VectorNormalize( v0->normal );
		}
	}
#else
	{
		float       bb, s, t;
		vec3_t      bary;
		vec3_t      faceNormal;
		md5Vertex_t *dv[ 3 ];

		for ( j = 0; j < sortedTriangles.currentElements; j++ )
		{
			skelTriangle_t *tri = Com_GrowListElement( &sortedTriangles, j );

			dv[ 0 ] = Com_GrowListElement( &vboVertexes, tri->indexes[ 0 ] );
			dv[ 1 ] = Com_GrowListElement( &vboVertexes, tri->indexes[ 1 ] );
			dv[ 2 ] = Com_GrowListElement( &vboVertexes, tri->indexes[ 2 ] );

			R_CalcNormalForTriangle( faceNormal, dv[ 0 ]->position, dv[ 1 ]->position, dv[ 2 ]->position );

			// calculate barycentric basis for the triangle
			bb = ( dv[ 1 ]->texCoords[ 0 ] - dv[ 0 ]->texCoords[ 0 ] ) * ( dv[ 2 ]->texCoords[ 1 ] - dv[ 0 ]->texCoords[ 1 ] ) - ( dv[ 2 ]->texCoords[ 0 ] - dv[ 0 ]->texCoords[ 0 ] ) * ( dv[ 1 ]->texCoords[ 1 ] -
			     dv[ 0 ]->texCoords[ 1 ] );

			if ( fabs( bb ) < 0.00000001f )
			{
				continue;
			}

			// do each vertex
			for ( k = 0; k < 3; k++ )
			{
				// calculate s tangent vector
				s = dv[ k ]->texCoords[ 0 ] + 10.0f;
				t = dv[ k ]->texCoords[ 1 ];
				bary[ 0 ] = ( ( dv[ 1 ]->texCoords[ 0 ] - s ) * ( dv[ 2 ]->texCoords[ 1 ] - t ) - ( dv[ 2 ]->texCoords[ 0 ] - s ) * ( dv[ 1 ]->texCoords[ 1 ] - t ) ) / bb;
				bary[ 1 ] = ( ( dv[ 2 ]->texCoords[ 0 ] - s ) * ( dv[ 0 ]->texCoords[ 1 ] - t ) - ( dv[ 0 ]->texCoords[ 0 ] - s ) * ( dv[ 2 ]->texCoords[ 1 ] - t ) ) / bb;
				bary[ 2 ] = ( ( dv[ 0 ]->texCoords[ 0 ] - s ) * ( dv[ 1 ]->texCoords[ 1 ] - t ) - ( dv[ 1 ]->texCoords[ 0 ] - s ) * ( dv[ 0 ]->texCoords[ 1 ] - t ) ) / bb;

				dv[ k ]->tangent[ 0 ] = bary[ 0 ] * dv[ 0 ]->position[ 0 ] + bary[ 1 ] * dv[ 1 ]->position[ 0 ] + bary[ 2 ] * dv[ 2 ]->position[ 0 ];
				dv[ k ]->tangent[ 1 ] = bary[ 0 ] * dv[ 0 ]->position[ 1 ] + bary[ 1 ] * dv[ 1 ]->position[ 1 ] + bary[ 2 ] * dv[ 2 ]->position[ 1 ];
				dv[ k ]->tangent[ 2 ] = bary[ 0 ] * dv[ 0 ]->position[ 2 ] + bary[ 1 ] * dv[ 1 ]->position[ 2 ] + bary[ 2 ] * dv[ 2 ]->position[ 2 ];

				VectorSubtract( dv[ k ]->tangent, dv[ k ]->position, dv[ k ]->tangent );
				VectorNormalize( dv[ k ]->tangent );

				// calculate t tangent vector (binormal)
				s = dv[ k ]->texCoords[ 0 ];
				t = dv[ k ]->texCoords[ 1 ] + 10.0f;
				bary[ 0 ] = ( ( dv[ 1 ]->texCoords[ 0 ] - s ) * ( dv[ 2 ]->texCoords[ 1 ] - t ) - ( dv[ 2 ]->texCoords[ 0 ] - s ) * ( dv[ 1 ]->texCoords[ 1 ] - t ) ) / bb;
				bary[ 1 ] = ( ( dv[ 2 ]->texCoords[ 0 ] - s ) * ( dv[ 0 ]->texCoords[ 1 ] - t ) - ( dv[ 0 ]->texCoords[ 0 ] - s ) * ( dv[ 2 ]->texCoords[ 1 ] - t ) ) / bb;
				bary[ 2 ] = ( ( dv[ 0 ]->texCoords[ 0 ] - s ) * ( dv[ 1 ]->texCoords[ 1 ] - t ) - ( dv[ 1 ]->texCoords[ 0 ] - s ) * ( dv[ 0 ]->texCoords[ 1 ] - t ) ) / bb;

				dv[ k ]->binormal[ 0 ] = bary[ 0 ] * dv[ 0 ]->position[ 0 ] + bary[ 1 ] * dv[ 1 ]->position[ 0 ] + bary[ 2 ] * dv[ 2 ]->position[ 0 ];
				dv[ k ]->binormal[ 1 ] = bary[ 0 ] * dv[ 0 ]->position[ 1 ] + bary[ 1 ] * dv[ 1 ]->position[ 1 ] + bary[ 2 ] * dv[ 2 ]->position[ 1 ];
				dv[ k ]->binormal[ 2 ] = bary[ 0 ] * dv[ 0 ]->position[ 2 ] + bary[ 1 ] * dv[ 1 ]->position[ 2 ] + bary[ 2 ] * dv[ 2 ]->position[ 2 ];

				VectorSubtract( dv[ k ]->binormal, dv[ k ]->position, dv[ k ]->binormal );
				VectorNormalize( dv[ k ]->binormal );

				// calculate the normal as cross product N=TxB
#if 0
				CrossProduct( dv[ k ]->tangent, dv[ k ]->binormal, dv[ k ]->normal );
				VectorNormalize( dv[ k ]->normal );

				// Gram-Schmidt orthogonalization process for B
				// compute the cross product B=NxT to obtain
				// an orthogonal basis
				CrossProduct( dv[ k ]->normal, dv[ k ]->tangent, dv[ k ]->binormal );

				if ( DotProduct( dv[ k ]->normal, faceNormal ) < 0 )
				{
					VectorInverse( dv[ k ]->normal );
					//VectorInverse(dv[k]->tangent);
					//VectorInverse(dv[k]->binormal);
				}

#else
				VectorAdd( dv[ k ]->normal, faceNormal, dv[ k ]->normal );
#endif
			}
		}

#if 1

		for ( j = 0; j < vboVertexes.currentElements; j++ )
		{
			dv[ 0 ] = Com_GrowListElement( &vboVertexes, j );
			//VectorNormalize(dv[0]->tangent);
			//VectorNormalize(dv[0]->binormal);
			VectorNormalize( dv[ 0 ]->normal );
		}

#endif
	}
#endif

#if 0
	{
		md5Vertex_t *v0, *v1;

		// do another extra smoothing for normals to avoid flat shading
		for ( j = 0; j < vboVertexes.currentElements; j++ )
		{
			v0 = Com_GrowListElement( &vboVertexes, j );

			for ( k = 0; k < vboVertexes.currentElements; k++ )
			{
				if ( j == k )
				{
					continue;
				}

				v1 = Com_GrowListElement( &vboVertexes, k );

				if ( VectorCompare( v0->position, v1->position ) )
				{
					VectorAdd( v0->position, v1->normal, v0->normal );
				}
			}

			VectorNormalize( v0->normal );
		}
	}
#endif

	// split the surfaces into VBO surfaces by the maximum number of GPU vertex skinning bones
	Com_InitGrowList( &vboSurfaces, 10 );

	materialIndex = oldMaterialIndex = -1;

	for ( i = 0; i < numTriangles; i++ )
	{
		triangle = &triangles[ i ];
		materialIndex = triangle->materialIndex;

		if ( materialIndex != oldMaterialIndex )
		{
			oldMaterialIndex = materialIndex;

			numRemaining = sortedTriangles.currentElements - i;

			while ( numRemaining )
			{
				numBoneReferences = 0;
				Com_Memset( boneReferences, 0, sizeof( boneReferences ) );

				Com_InitGrowList( &vboTriangles, 1000 );

				for ( j = i; j < sortedTriangles.currentElements; j++ )
				{
					skelTriangle_t *sortTri;

					triangle = &triangles[ j ];
					materialIndex = triangle->materialIndex;

					if ( materialIndex != oldMaterialIndex )
					{
						continue;
					}

					sortTri = (skelTriangle_t*) Com_GrowListElement( &sortedTriangles, j );

					if ( sortTri->referenced )
					{
						continue;
					}

					if ( AddTriangleToVBOTriangleList( &vboTriangles, sortTri, &numBoneReferences, boneReferences ) )
					{
						sortTri->referenced = qtrue;
					}
				}

				for ( j = 0; j < MAX_BONES; j++ )
				{
					if ( boneReferences[ j ] > 0 )
					{
						ri.Printf( PRINT_ALL, "R_LoadPSK: referenced bone: '%s'\n", ( j < numReferenceBones ) ? refBones[ j ].name : NULL );
					}
				}

				if ( !vboTriangles.currentElements )
				{
					ri.Printf( PRINT_WARNING, "R_LoadPSK: could not add triangles to a remaining VBO surface for model '%s'\n", modName );
					break;
				}

				// FIXME skinIndex
				AddSurfaceToVBOSurfacesList2( &vboSurfaces, &vboTriangles, &vboVertexes, md5, vboSurfaces.currentElements, materials[ oldMaterialIndex ].name, numBoneReferences, boneReferences );
				numRemaining -= vboTriangles.currentElements;

				Com_DestroyGrowList( &vboTriangles );
			}
		}
	}

	for ( j = 0; j < sortedTriangles.currentElements; j++ )
	{
		skelTriangle_t *sortTri = (skelTriangle_t*) Com_GrowListElement( &sortedTriangles, j );
		Com_Dealloc( sortTri );
	}

	Com_DestroyGrowList( &sortedTriangles );

	for ( j = 0; j < vboVertexes.currentElements; j++ )
	{
		md5Vertex_t *v = (md5Vertex_t*) Com_GrowListElement( &vboVertexes, j );
		Com_Dealloc( v );
	}

	Com_DestroyGrowList( &vboVertexes );

	// move VBO surfaces list to hunk
	md5->numVBOSurfaces = vboSurfaces.currentElements;
	md5->vboSurfaces = (srfVBOMD5Mesh_t**) ri.Hunk_Alloc( md5->numVBOSurfaces * sizeof( *md5->vboSurfaces ), h_low );

	for ( i = 0; i < md5->numVBOSurfaces; i++ )
	{
		md5->vboSurfaces[ i ] = ( srfVBOMD5Mesh_t * ) Com_GrowListElement( &vboSurfaces, i );
	}

	Com_DestroyGrowList( &vboSurfaces );

	FreeMemStream( stream );
	Com_Dealloc( points );
	Com_Dealloc( vertexes );
	Com_Dealloc( triangles );
	Com_Dealloc( materials );

	ri.Printf( PRINT_DEVELOPER, "%i VBO surfaces created for PSK model '%s'\n", md5->numVBOSurfaces, modName );

	return qtrue;
}
Example #11
0
void AddTriangleModels(entity_t * e)
{
	int             num, frame, castShadows, recvShadows, spawnFlags;
	entity_t       *e2;
	const char     *targetName;
	const char     *target, *model, *value;
	char            shader[MAX_QPATH];
	shaderInfo_t   *celShader;
	float           temp, baseLightmapScale, lightmapScale;
	float           shadeAngle;
	int             lightmapSampleSize;
	vec3_t          origin, scale, angles;
	matrix_t        rotation, rotationScaled, transform;
	epair_t        *ep;
	remap_t        *remap, *remap2;
	char           *split;


	/* note it */
	Sys_FPrintf(SYS_VRB, "--- AddTriangleModels ---\n");

	/* get current brush entity targetname */
	if(e == entities)
		targetName = "";
	else
	{
		targetName = ValueForKey(e, "name");

		/* misc_model entities target non-worldspawn brush model entities */
		if(targetName[0] == '\0')
			return;
	}

	/* get lightmap scale */
	/* vortex: added _ls key (short name of lightmapscale) */
	baseLightmapScale = 0.0f;
	if(strcmp("", ValueForKey(e, "lightmapscale")) ||
	   strcmp("", ValueForKey(e, "_lightmapscale")) || strcmp("", ValueForKey(e, "_ls")))
	{
		baseLightmapScale = FloatForKey(e, "lightmapscale");
		if(baseLightmapScale <= 0.0f)
			baseLightmapScale = FloatForKey(e, "_lightmapscale");
		if(baseLightmapScale <= 0.0f)
			baseLightmapScale = FloatForKey(e, "_ls");
		if(baseLightmapScale < 0.0f)
			baseLightmapScale = 0.0f;
		if(baseLightmapScale > 0.0f)
			Sys_Printf("World Entity has lightmap scale of %.4f\n", baseLightmapScale);
	}

	/* walk the entity list */
	for(num = 1; num < numEntities; num++)
	{
		/* get e2 */
		e2 = &entities[num];

		/* convert misc_models into raw geometry */
		if(Q_stricmp("misc_model", ValueForKey(e2, "classname")))
			continue;

		/* ydnar: added support for md3 models on non-worldspawn models */
		target = ValueForKey(e2, "target");
		if(strcmp(target, targetName))
			continue;

		/* get model name */
		model = ValueForKey(e2, "model");
		if(model[0] == '\0')
		{
			Sys_Printf("WARNING: misc_model at %i %i %i without a model key\n", (int)origin[0], (int)origin[1], (int)origin[2]);
			continue;
		}

		/* get model frame */
		frame = IntForKey(e2, "_frame");

		/* worldspawn (and func_groups) default to cast/recv shadows in worldspawn group */
		if(e == entities)
		{
			castShadows = WORLDSPAWN_CAST_SHADOWS;
			recvShadows = WORLDSPAWN_RECV_SHADOWS;
		}

		/* other entities don't cast any shadows, but recv worldspawn shadows */
		else
		{
			castShadows = ENTITY_CAST_SHADOWS;
			recvShadows = ENTITY_RECV_SHADOWS;
		}

		/* get explicit shadow flags */
		GetEntityShadowFlags(e2, e, &castShadows, &recvShadows);

		/* get spawnflags */
		spawnFlags = IntForKey(e2, "spawnflags");

		/* Tr3B: added clipModel option */
		spawnFlags |= (IntForKey(e2, "clipModel") > 0) ? 2 : 0;

		/* Tr3B: added forceMeta option */
		spawnFlags |= (IntForKey(e2, "forceMeta") > 0) ? 4 : 0;

		/* get origin */
		GetVectorForKey(e2, "origin", origin);
		VectorSubtract(origin, e->origin, origin);	/* offset by parent */

		/* get "angle" (yaw) or "angles" (pitch yaw roll) */
		MatrixIdentity(rotation);
		angles[0] = angles[1] = angles[2] = 0.0f;

		value = ValueForKey(e2, "angle");
		if(value[0] != '\0')
		{
			angles[1] = atof(value);
			MatrixFromAngles(rotation, angles[PITCH], angles[YAW], angles[ROLL]);
		}

		value = ValueForKey(e2, "angles");
		if(value[0] != '\0')
		{
			sscanf(value, "%f %f %f", &angles[0], &angles[1], &angles[2]);
			MatrixFromAngles(rotation, angles[PITCH], angles[YAW], angles[ROLL]);
		}

		value = ValueForKey(e2, "rotation");
		if(value[0] != '\0')
		{
			sscanf(value, "%f %f %f %f %f %f %f %f %f", &rotation[0], &rotation[1], &rotation[2],
				   &rotation[4], &rotation[5], &rotation[6], &rotation[8], &rotation[9], &rotation[10]);
		}

		/* get scale */
		scale[0] = scale[1] = scale[2] = 1.0f;
		temp = FloatForKey(e2, "modelscale");
		if(temp != 0.0f)
			scale[0] = scale[1] = scale[2] = temp;
		value = ValueForKey(e2, "modelscale_vec");
		if(value[0] != '\0')
			sscanf(value, "%f %f %f", &scale[0], &scale[1], &scale[2]);

		MatrixCopy(rotation, rotationScaled);
		MatrixMultiplyScale(rotationScaled, scale[0], scale[1], scale[2]);

		/* set transform matrix */
		MatrixIdentity(transform);
		MatrixSetupTransformFromRotation(transform, rotationScaled, origin);

		/* get shader remappings */
		remap = NULL;
		for(ep = e2->epairs; ep != NULL; ep = ep->next)
		{
			/* look for keys prefixed with "_remap" */
			if(ep->key != NULL && ep->value != NULL &&
			   ep->key[0] != '\0' && ep->value[0] != '\0' && !Q_strncasecmp(ep->key, "_remap", 6))
			{
				/* create new remapping */
				remap2 = remap;
				remap = safe_malloc(sizeof(*remap));
				remap->next = remap2;
				strcpy(remap->from, ep->value);

				/* split the string */
				split = strchr(remap->from, ';');
				if(split == NULL)
				{
					Sys_Printf("WARNING: Shader _remap key found in misc_model without a ; character\n");
					free(remap);
					remap = remap2;
					continue;
				}

				/* store the split */
				*split = '\0';
				strcpy(remap->to, (split + 1));

				/* note it */
				//% Sys_FPrintf( SYS_VRB, "Remapping %s to %s\n", remap->from, remap->to );
			}
		}

		/* ydnar: cel shader support */
		value = ValueForKey(e2, "_celshader");
		if(value[0] == '\0')
			value = ValueForKey(&entities[0], "_celshader");
		if(value[0] != '\0')
		{
			sprintf(shader, "textures/%s", value);
			celShader = ShaderInfoForShader(shader);
		}
		else
			celShader = NULL;

		/* jal : entity based _samplesize */
		lightmapSampleSize = 0;
		if(strcmp("", ValueForKey(e2, "_lightmapsamplesize")))
			lightmapSampleSize = IntForKey(e2, "_lightmapsamplesize");
		else if(strcmp("", ValueForKey(e2, "_samplesize")))
			lightmapSampleSize = IntForKey(e2, "_samplesize");

		if(lightmapSampleSize < 0)
			lightmapSampleSize = 0;

		if(lightmapSampleSize > 0.0f)
			Sys_Printf("misc_model has lightmap sample size of %.d\n", lightmapSampleSize);

		/* get lightmap scale */
		/* vortex: added _ls key (short name of lightmapscale) */
		lightmapScale = 0.0f;
		if(strcmp("", ValueForKey(e2, "lightmapscale")) ||
		   strcmp("", ValueForKey(e2, "_lightmapscale")) || strcmp("", ValueForKey(e2, "_ls")))
		{
			lightmapScale = FloatForKey(e2, "lightmapscale");
			if(lightmapScale <= 0.0f)
				lightmapScale = FloatForKey(e2, "_lightmapscale");
			if(lightmapScale <= 0.0f)
				lightmapScale = FloatForKey(e2, "_ls");
			if(lightmapScale < 0.0f)
				lightmapScale = 0.0f;
			if(lightmapScale > 0.0f)
				Sys_Printf("misc_model has lightmap scale of %.4f\n", lightmapScale);
		}

		/* jal : entity based _shadeangle */
		shadeAngle = 0.0f;
		if(strcmp("", ValueForKey(e2, "_shadeangle")))
			shadeAngle = FloatForKey(e2, "_shadeangle");
		/* vortex' aliases */
		else if(strcmp("", ValueForKey(mapEnt, "_smoothnormals")))
			shadeAngle = FloatForKey(mapEnt, "_smoothnormals");
		else if(strcmp("", ValueForKey(mapEnt, "_sn")))
			shadeAngle = FloatForKey(mapEnt, "_sn");
		else if(strcmp("", ValueForKey(mapEnt, "_smooth")))
			shadeAngle = FloatForKey(mapEnt, "_smooth");

		if(shadeAngle < 0.0f)
			shadeAngle = 0.0f;

		if(shadeAngle > 0.0f)
			Sys_Printf("misc_model has shading angle of %.4f\n", shadeAngle);

		/* insert the model */
		InsertModel((char *)model, frame, transform, rotation, remap, celShader, mapEntityNum, castShadows, recvShadows, spawnFlags,
					lightmapScale, lightmapSampleSize, shadeAngle);

		/* free shader remappings */
		while(remap != NULL)
		{
			remap2 = remap->next;
			free(remap);
			remap = remap2;
		}
	}
}
static int vmatrix_MatrixFromAngles (lua_State *L) {
  MatrixFromAngles(luaL_checkangle(L, 1), luaL_checkvmatrix(L, 2));
  return 0;
}