예제 #1
0
파일: tr_init.cpp 프로젝트: AlexXT/OpenJK
void R_Init( void ) {
	int i;
	byte *ptr;

//	Com_Printf ("----- R_Init -----\n" );
	// clear all our internal state
	memset( &tr, 0, sizeof( tr ) );
	memset( &backEnd, 0, sizeof( backEnd ) );

//	Swap_Init();

	//
	// init function tables
	//
	for ( i = 0; i < FUNCTABLE_SIZE; i++ )
	{
		tr.sinTable[i]		= sin( DEG2RAD( i * 360.0f / ( ( float ) ( FUNCTABLE_SIZE - 1 ) ) ) );
		tr.squareTable[i]	= ( i < FUNCTABLE_SIZE/2 ) ? 1.0f : -1.0f;
		tr.sawToothTable[i] = (float)i / FUNCTABLE_SIZE;
		tr.inverseSawToothTable[i] = 1.0f - tr.sawToothTable[i];

		if ( i < FUNCTABLE_SIZE / 2 )
		{
			if ( i < FUNCTABLE_SIZE / 4 )
			{
				tr.triangleTable[i] = ( float ) i / ( FUNCTABLE_SIZE / 4 );
			}
			else
			{
				tr.triangleTable[i] = 1.0f - tr.triangleTable[i-FUNCTABLE_SIZE / 4];
			}
		}
		else
		{
			tr.triangleTable[i] = -tr.triangleTable[i-FUNCTABLE_SIZE/2];
		}
	}
	R_Register();

	max_polys = Q_min( r_maxpolys->integer, DEFAULT_MAX_POLYS );
	max_polyverts = Q_min( r_maxpolyverts->integer, DEFAULT_MAX_POLYVERTS );

	ptr = (byte *)Hunk_Alloc( sizeof( *backEndData ) + sizeof(srfPoly_t) * max_polys + sizeof(polyVert_t) * max_polyverts, h_low);
	backEndData = (backEndData_t *) ptr;
	backEndData->polys = (srfPoly_t *) ((char *) ptr + sizeof( *backEndData ));
	backEndData->polyVerts = (polyVert_t *) ((char *) ptr + sizeof( *backEndData ) + sizeof(srfPoly_t) * max_polys);

	R_ModelInit();

//	Com_Printf ("----- finished R_Init -----\n" );
}
예제 #2
0
void WIN_SetGamma( glconfig_t *glConfig, byte red[256], byte green[256], byte blue[256] )
{
	Uint16 table[3][256];
	int i, j;

	if( !glConfig->deviceSupportsGamma || r_ignorehwgamma->integer > 0 )
		return;

	for (i = 0; i < 256; i++)
	{
		table[0][i] = ( ( ( Uint16 ) red[i] ) << 8 ) | red[i];
		table[1][i] = ( ( ( Uint16 ) green[i] ) << 8 ) | green[i];
		table[2][i] = ( ( ( Uint16 ) blue[i] ) << 8 ) | blue[i];
	}

#if defined(_WIN32)
	// Win2K and newer put this odd restriction on gamma ramps...
	{
		OSVERSIONINFO	vinfo;

		vinfo.dwOSVersionInfoSize = sizeof( vinfo );
		GetVersionEx( &vinfo );
		if( vinfo.dwMajorVersion >= 5 && vinfo.dwPlatformId == VER_PLATFORM_WIN32_NT )
		{
			Com_DPrintf( "performing gamma clamp.\n" );
			for( j = 0 ; j < 3 ; j++ )
			{
				for( i = 0 ; i < 128 ; i++ )
				{
					table[j][i] = Q_min(table[j][i], (128 + i) << 8);
				}

				table[j][127] = Q_min(table[j][127], 254 << 8);
			}
		}
	}
#endif

	// enforce constantly increasing
	for (j = 0; j < 3; j++)
	{
		for (i = 1; i < 256; i++)
		{
			if (table[j][i] < table[j][i-1])
				table[j][i] = table[j][i-1];
		}
	}

	SDL_SetWindowGammaRamp(screen, table[0], table[1], table[2]);
}
예제 #3
0
BOOL CItemBattery::__MAKE_VHOOK(MyTouch)(CBasePlayer *pPlayer)
{
	if (pPlayer->pev->armorvalue < MAX_NORMAL_BATTERY && (pPlayer->pev->weapons & (1 << WEAPON_SUIT)))
	{
		int pct;
		char szcharge[64];

		pPlayer->pev->armorvalue += gSkillData.batteryCapacity;
		pPlayer->pev->armorvalue = Q_min(pPlayer->pev->armorvalue, MAX_NORMAL_BATTERY);

		EMIT_SOUND(pPlayer->edict(), CHAN_ITEM, "items/gunpickup2.wav", VOL_NORM, ATTN_NORM);

		MESSAGE_BEGIN(MSG_ONE, gmsgItemPickup, NULL, pPlayer->pev);
			WRITE_STRING(STRING(pev->classname));
		MESSAGE_END();

		// Suit reports new power level
		// For some reason this wasn't working in release build -- round it.
		pct = int(float(pPlayer->pev->armorvalue * 100.0f) * (1.0f / MAX_NORMAL_BATTERY) + 0.5f);
		pct = (pct / 5);

		if (pct > 0)
			pct--;

		Q_sprintf(szcharge,"!HEV_%1dP", pct);
		pPlayer->SetSuitUpdate(szcharge, FALSE, SUIT_NEXT_IN_30SEC);

		return TRUE;
	}
	return FALSE;
}
예제 #4
0
void CGib::BounceGibTouch(CBaseEntity *pOther)
{
	if (pev->flags & FL_ONGROUND)
	{
		pev->velocity = pev->velocity * 0.9;
		pev->angles.x = 0;
		pev->angles.z = 0;
		pev->avelocity.x = 0;
		pev->avelocity.z = 0;
	}
	else
	{
		if (g_Language != LANGUAGE_GERMAN && m_cBloodDecals > 0 && m_bloodColor != DONT_BLEED)
		{
			TraceResult tr;
			Vector vecSpot = pev->origin + Vector(0, 0, 8);
			UTIL_TraceLine(vecSpot, vecSpot + Vector(0, 0, -24), ignore_monsters, ENT(pev), &tr);
			UTIL_BloodDecalTrace(&tr, m_bloodColor);
			m_cBloodDecals--;
		}

		if (m_material != matNone && !RANDOM_LONG(0, 2))
		{
			float zvel = Q_fabs(pev->velocity.z);
			float volume = 0.8 * Q_min(1.0f, zvel / 450);

			CBreakable::MaterialSoundRandom(edict(), (Materials)m_material, volume);
		}
	}
}
예제 #5
0
void CFuncVehicle::Blocked(CBaseEntity *pOther)
{
	entvars_t *pevOther = pOther->pev;

	if ((pevOther->flags & FL_ONGROUND) && VARS(pevOther->groundentity) == pev)
	{
		pevOther->velocity = pev->velocity;
		return;
	}

	pevOther->velocity = (pevOther->origin - pev->origin).Normalize() * pev->dmg;
	pevOther->velocity.z += 300;
	pev->velocity = pev->velocity * 0.85;

	ALERT(at_aiconsole, "TRAIN(%s): Blocked by %s (dmg:%.2f)\n", STRING(pev->targetname), STRING(pOther->pev->classname), pev->dmg);
	UTIL_MakeVectors(pev->angles);

	Vector forward, right, vOrigin;
	Vector vFrontLeft = (gpGlobals->v_forward * -1) * (m_length * 0.5);
	Vector vFrontRight = (gpGlobals->v_right * -1) * (m_width * 0.5);

	Vector vBackLeft = pev->origin + vFrontLeft - vFrontRight;
	Vector vBackRight = pev->origin - vFrontLeft + vFrontRight;

	float minx = Q_min(vBackLeft.x, vBackRight.x);
	float miny = Q_min(vBackLeft.y, vBackRight.y);
	float maxx = Q_max(vBackLeft.x, vBackRight.x);
	float maxy = Q_max(vBackLeft.y, vBackRight.y);

	float minz = pev->origin.z;
#ifdef REGAMEDLL_FIXES
	float maxz = pev->origin.z + (2 * Q_abs(pev->mins.z - pev->maxs.z));	
#else
	float maxz = pev->origin.z + (2 * Q_abs(int(pev->mins.z - pev->maxs.z)));
#endif

	if (pOther->pev->origin.x < minx
		|| pOther->pev->origin.x > maxx
		|| pOther->pev->origin.y < miny
		|| pOther->pev->origin.y > maxy
		|| pOther->pev->origin.z < pev->origin.z
		|| pOther->pev->origin.z > maxz)
	{
		pOther->TakeDamage(pev, pev, 150, DMG_CRUSH);
	}
}
예제 #6
0
/**
 * @brief Convert a Java string (which is Unicode) to reasonable 7-bit ASCII.
 *
 * @author Berry Pederson
 */
void ConvertJavaString(char *dest, jstring jstr, int destsize)
{
	jsize           jStrLen;
	const jchar    *unicodeChars;

//  char           *result;
	int             i;
	char           *p;

	// table for translating accented latin-1 characters to closest non-accented chars
	// Icelandic thorn and eth are difficult, so I just used an asterisk
	// German sz ligature � is also difficult, chose to just put in 's'
	// AE ligatures are just replaced with *
	// perhaps some sort of multi-character substitution scheme would be helpful
	//
	// this translation table starts at decimal 192 (capital A, grave accent: �)
	static char    *translateTable = "AAAAAA*CEEEEIIIIDNOOOOOxOUUUUY*saaaaaa*ceeeeiiii*nooooo/ouuuuy*y";

	if(!jstr)
	{
		Com_Error(ERR_FATAL, "ConvertJavaString: NULL src");
	}

	if(destsize < 1)
	{
		Com_Error(ERR_FATAL, "ConvertJavaString: destsize < 1");
	}



	jStrLen = Q_min((*javaEnv)->GetStringLength(javaEnv, jstr), destsize);

	p = dest;					// = q2java_gi.TagMalloc(jStrLen + 1, TAG_GAME);
	unicodeChars = (*javaEnv)->GetStringChars(javaEnv, jstr, NULL);

	for(i = 0; i < jStrLen; i++)
	{
		jchar           ch = unicodeChars[i];

		if(ch < 192)
			*p++ = (char)ch;
		else
		{
			if(ch < 256)
				*p++ = translateTable[ch - 192];
			else
				*p++ = '*';
		}

	}

	(*javaEnv)->ReleaseStringChars(javaEnv, jstr, unicodeChars);
	*p = 0;

//  return result;
}
예제 #7
0
static const char *GetErrorString( DWORD error ) {
	static char buf[MAX_STRING_CHARS];
	buf[0] = '\0';

	if ( error ) {
		LPVOID lpMsgBuf;
		DWORD bufLen = FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
			NULL, error, MAKELANGID( LANG_NEUTRAL, SUBLANG_DEFAULT ), (LPTSTR)&lpMsgBuf, 0, NULL );
		if ( bufLen ) {
			LPCSTR lpMsgStr = (LPCSTR)lpMsgBuf;
			Q_strncpyz( buf, lpMsgStr, Q_min( (size_t)(lpMsgStr + bufLen), sizeof(buf) ) );
			LocalFree( lpMsgBuf );
		}
	}
	return buf;
}
예제 #8
0
// Set the current index along the path
void CCSBot::SetPathIndex(int newIndex)
{
	m_pathIndex = Q_min(newIndex, m_pathLength - 1);
	m_areaEnteredTimestamp = gpGlobals->time;

	if (m_path[m_pathIndex].ladder)
	{
		SetupLadderMovement();
	}
	else
	{
		// get our "encounter spots" for this leg of the path
		if (m_pathIndex < m_pathLength && m_pathIndex >= 2)
			m_spotEncounter = m_path[m_pathIndex - 1].area->GetSpotEncounter(m_path[m_pathIndex - 2].area, m_path[m_pathIndex].area);
		else
			m_spotEncounter = nullptr;

		m_pathLadder = nullptr;
	}
}
예제 #9
0
/*
=====================
CBasePlayerWeapon::DefaultReload
=====================
*/
BOOL CBasePlayerWeapon::DefaultReload( int iClipSize, int iAnim, float fDelay, int body )
{
	if( m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] <= 0 )
		return FALSE;

	int j = Q_min( iClipSize - m_iClip, m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] );

	if( j == 0 )
		return FALSE;

	m_pPlayer->m_flNextAttack = UTIL_WeaponTimeBase() + fDelay;

	//!!UNDONE -- reload sound goes here !!!
	SendWeaponAnim( iAnim, UseDecrement(), body );

	m_fInReload = TRUE;

	m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 3;
	return TRUE;
}
예제 #10
0
파일: sv_client.cpp 프로젝트: Avygeil/NewJK
/*
=================
SV_UserinfoChanged

Pull specific info from a newly changed userinfo string
into a more C friendly form.
=================
*/
void SV_UserinfoChanged( client_t *cl ) {
	char	*val=NULL, *ip=NULL;
	int		i=0, len=0;

	// name for C code
	Q_strncpyz( cl->name, Info_ValueForKey (cl->userinfo, "name"), sizeof(cl->name) );

	// rate command

	// if the client is on the same subnet as the server and we aren't running an
	// internet public server, assume they don't need a rate choke
	if ( Sys_IsLANAddress( cl->netchan.remoteAddress ) && com_dedicated->integer != 2 && sv_lanForceRate->integer == 1 ) {
		cl->rate = 99999;	// lans should not rate limit
	} else {
		val = Info_ValueForKey (cl->userinfo, "rate");
		if (strlen(val)) {
			i = atoi(val);
			cl->rate = i;
			if (cl->rate < 1000) {
				cl->rate = 1000;
			} else if (cl->rate > 90000) {
				cl->rate = 90000;
			}
		} else {
			cl->rate = 3000;
		}
	}

	// snaps command
	//Note: cl->snapshotMsec is also validated in sv_main.cpp -> SV_CheckCvars if sv_fps, sv_snapsMin or sv_snapsMax is changed
	int minSnaps = Com_Clampi( 1, sv_snapsMax->integer, sv_snapsMin->integer ); // between 1 and sv_snapsMax ( 1 <-> 40 )
	int maxSnaps = Q_min( sv_fps->integer, sv_snapsMax->integer ); // can't produce more than sv_fps snapshots/sec, but can send less than sv_fps snapshots/sec
	val = Info_ValueForKey( cl->userinfo, "snaps" );
	cl->wishSnaps = atoi( val );
	if ( !cl->wishSnaps )
		cl->wishSnaps = maxSnaps;
	i = 1000/Com_Clampi( minSnaps, maxSnaps, cl->wishSnaps );
	if( i != cl->snapshotMsec ) {
		// Reset next snapshot so we avoid desync between server frame time and snapshot send time
		cl->nextSnapshotTime = -1;
		cl->snapshotMsec = i;
	}

	// TTimo
	// maintain the IP information
	// the banning code relies on this being consistently present
	if( NET_IsLocalAddress(cl->netchan.remoteAddress) )
		ip = "localhost";
	else
		ip = (char*)NET_AdrToString( cl->netchan.remoteAddress );

	val = Info_ValueForKey( cl->userinfo, "ip" );
	if( val[0] )
		len = strlen( ip ) - strlen( val ) + strlen( cl->userinfo );
	else
		len = strlen( ip ) + 4 + strlen( cl->userinfo );

	if( len >= MAX_INFO_STRING )
		SV_DropClient( cl, "userinfo string length exceeded" );
	else
		Info_SetValueForKey( cl->userinfo, "ip", ip );
}
예제 #11
0
static void AddSurfaceToVBOSurfacesListMDM(growList_t * vboSurfaces, growList_t * vboTriangles, mdmModel_t * mdm, mdmSurfaceIntern_t * surf, int skinIndex, int numBoneReferences, int boneReferences[MAX_BONES])
{
	int				j, k, lod;

	int             vertexesNum;
	byte           *data;
	int             dataSize;
	int             dataOfs;

	GLuint          ofsTexCoords;
	GLuint          ofsTangents;
	GLuint          ofsBinormals;
	GLuint          ofsNormals;
	GLuint          ofsBoneIndexes;
	GLuint          ofsBoneWeights;

	int             indexesNum;
	byte           *indexes;
	int             indexesSize;
	int             indexesOfs;

	skelTriangle_t  *tri;

	vec4_t          tmp;
	int             index;

	srfVBOMDMMesh_t *vboSurf;
	md5Vertex_t     *v;

	vec4_t          tmpColor = { 1, 1, 1, 1 };

	static int32_t  collapse[MDM_MAX_VERTS];


	vertexesNum = surf->numVerts;
	indexesNum = vboTriangles->currentElements * 3;

	// create surface
	vboSurf = ri.Hunk_Alloc(sizeof(*vboSurf), h_low);
	Com_AddToGrowList(vboSurfaces, vboSurf);

	vboSurf->surfaceType = SF_VBO_MDMMESH;
	vboSurf->mdmModel = mdm;
	vboSurf->mdmSurface = surf;
	vboSurf->shader = R_GetShaderByHandle(surf->shaderIndex);
	vboSurf->skinIndex = skinIndex;
	vboSurf->numIndexes = indexesNum;
	vboSurf->numVerts = vertexesNum;

	dataSize = vertexesNum * (sizeof(vec4_t) * 7);
	data = ri.Malloc(dataSize);
	dataOfs = 0;

	

	//ri.Printf(PRINT_ALL, "AddSurfaceToVBOSurfacesList( %i verts, %i tris )\n", surf->numVerts, vboTriangles->currentElements);

	vboSurf->numBoneRemap = 0;
	Com_Memset(vboSurf->boneRemap, 0, sizeof(vboSurf->boneRemap));
	Com_Memset(vboSurf->boneRemapInverse, 0, sizeof(vboSurf->boneRemapInverse));

	//ri.Printf(PRINT_ALL, "original referenced bones: [ ");
	//for(j = 0; j < surf->numBoneReferences; j++)
	//{
	//	ri.Printf(PRINT_ALL, "%i, ", surf->boneReferences[j]);
	//}
	//ri.Printf(PRINT_ALL, "]\n");

	//ri.Printf(PRINT_ALL, "new referenced bones: ");
	for(j = 0; j < MAX_BONES; j++)
	{
		if(boneReferences[j] > 0)
		{
			vboSurf->boneRemap[j] = vboSurf->numBoneRemap;
			vboSurf->boneRemapInverse[vboSurf->numBoneRemap] = j;

			vboSurf->numBoneRemap++;

			//ri.Printf(PRINT_ALL, "(%i -> %i) ", j, vboSurf->boneRemap[j]);
		}
	}
	//ri.Printf(PRINT_ALL, "\n");

	// feed vertex XYZ
	for(j = 0; j < vertexesNum; j++)
	{
		for(k = 0; k < 3; k++)
		{
			tmp[k] = surf->verts[j].position[k];
		}
		tmp[3] = 1;
		Com_Memcpy(data + dataOfs, (vec_t *) tmp, sizeof(vec4_t));
		dataOfs += sizeof(vec4_t);
	}

	// feed vertex texcoords
	ofsTexCoords = dataOfs;
	for(j = 0; j < vertexesNum; j++)
	{
		for(k = 0; k < 2; k++)
		{
			tmp[k] = surf->verts[j].texCoords[k];
		}
		tmp[2] = 0;
		tmp[3] = 1;
		Com_Memcpy(data + dataOfs, (vec_t *) tmp, sizeof(vec4_t));
		dataOfs += sizeof(vec4_t);
	}

	// feed vertex tangents
	ofsTangents = dataOfs;
	for(j = 0; j < vertexesNum; j++)
	{
		for(k = 0; k < 3; k++)
		{
			tmp[k] = surf->verts[j].tangent[k];
		}
		tmp[3] = 1;
		Com_Memcpy(data + dataOfs, (vec_t *) tmp, sizeof(vec4_t));
		dataOfs += sizeof(vec4_t);
	}

	// feed vertex binormals
	ofsBinormals = dataOfs;
	for(j = 0; j < vertexesNum; j++)
	{
		for(k = 0; k < 3; k++)
		{
			tmp[k] = surf->verts[j].binormal[k];
		}
		tmp[3] = 1;
		Com_Memcpy(data + dataOfs, (vec_t *) tmp, sizeof(vec4_t));
		dataOfs += sizeof(vec4_t);
	}

	// feed vertex normals
	ofsNormals = dataOfs;
	for(j = 0; j < vertexesNum; j++)
	{
		for(k = 0; k < 3; k++)
		{
			tmp[k] = surf->verts[j].normal[k];
		}
		tmp[3] = 1;
		Com_Memcpy(data + dataOfs, (vec_t *) tmp, sizeof(vec4_t));
		dataOfs += sizeof(vec4_t);
	}

	// feed bone indices
	ofsBoneIndexes = dataOfs;
	for(j = 0, v = surf->verts; j < surf->numVerts; j++, v++)
	{
		for(k = 0; k < MAX_WEIGHTS; k++)
		{
			if(k < v->numWeights)
				index = vboSurf->boneRemap[v->weights[k]->boneIndex];
			else
				index = 0;

			Com_Memcpy(data + dataOfs, &index, sizeof(int));
			dataOfs += sizeof(int);
		}
	}

	// feed bone weights
	ofsBoneWeights = dataOfs;
	for(j = 0, v = surf->verts; j < surf->numVerts; j++, v++)
	{
		for(k = 0; k < MAX_WEIGHTS; k++)
		{
			if(k < v->numWeights)
				tmp[k] = v->weights[k]->boneWeight;
			else
				tmp[k] = 0;
		}
		Com_Memcpy(data + dataOfs, (vec_t *) tmp, sizeof(vec4_t));
		dataOfs += sizeof(vec4_t);
	}

	vboSurf->vbo = R_CreateVBO(va("staticMDMMesh_VBO %i", vboSurfaces->currentElements), data, dataSize, VBO_USAGE_STATIC);
	vboSurf->vbo->ofsXYZ = 0;
	vboSurf->vbo->ofsTexCoords = ofsTexCoords;
	vboSurf->vbo->ofsLightCoords = ofsTexCoords;
	vboSurf->vbo->ofsTangents = ofsTangents;
	vboSurf->vbo->ofsBinormals = ofsBinormals;
	vboSurf->vbo->ofsNormals = ofsNormals;
	vboSurf->vbo->ofsColors = ofsNormals;
	vboSurf->vbo->ofsLightCoords = 0;		// not required anyway
	vboSurf->vbo->ofsLightDirections = 0;	// not required anyway
	vboSurf->vbo->ofsBoneIndexes = ofsBoneIndexes;
	vboSurf->vbo->ofsBoneWeights = ofsBoneWeights;

	// calculate LOD IBOs
	lod = 0;
	do
	{
		float		flod;
		int			renderCount;
		
		flod = mdmLODResolutions[lod];

		renderCount = Q_min((int)((float)surf->numVerts * flod), surf->numVerts);

		if(renderCount < surf->minLod)
		{
			renderCount = surf->minLod;
			flod = (float)renderCount / surf->numVerts;
		}

		if(renderCount == surf->numVerts)
		{
			indexesNum = vboTriangles->currentElements * 3;
			indexesSize = indexesNum * sizeof(int);
			indexes = ri.Malloc(indexesSize);
			indexesOfs = 0;

			for(j = 0; j < vboTriangles->currentElements; j++)
			{
				tri = Com_GrowListElement(vboTriangles, j);

				for(k = 0; k < 3; k++)
				{
					index = tri->indexes[k];

					Com_Memcpy(indexes + indexesOfs, &index, sizeof(int));
					indexesOfs += sizeof(int);
				}
			}
		}
		else
		{
			int				ci[3];
			int32_t        *pCollapseMap;
			int32_t        *pCollapse;

			pCollapse = collapse;
			for(j = 0; j < renderCount; pCollapse++, j++)
			{
				*pCollapse = j;
			}

			pCollapseMap = &surf->collapseMap[renderCount];
			for(j = renderCount; j < surf->numVerts; j++, pCollapse++, pCollapseMap++)
			{
				int32_t collapseValue = *pCollapseMap;
				*pCollapse = collapse[collapseValue];
			}


			indexesNum = 0;
			for(j = 0; j < vboTriangles->currentElements; j++)
			{
				tri = Com_GrowListElement(vboTriangles, j);

				ci[0] = collapse[tri->indexes[0]];
				ci[1] = collapse[tri->indexes[1]];
				ci[2] = collapse[tri->indexes[2]];

				// FIXME
				// note:  serious optimization opportunity here,
				//  by sorting the triangles the following "continue"
				//  could have been made into a "break" statement.
				if(ci[0] == ci[1] || ci[1] == ci[2] || ci[2] == ci[0])
				{
					continue;
				}

				indexesNum += 3;
			}


			indexesSize = indexesNum * sizeof(int);
			indexes = ri.Malloc(indexesSize);
			indexesOfs = 0;

			for(j = 0; j < vboTriangles->currentElements; j++)
			{
				tri = Com_GrowListElement(vboTriangles, j);

				ci[0] = collapse[tri->indexes[0]];
				ci[1] = collapse[tri->indexes[1]];
				ci[2] = collapse[tri->indexes[2]];

				// FIXME
				// note:  serious optimization opportunity here,
				//  by sorting the triangles the following "continue"
				//  could have been made into a "break" statement.
				if(ci[0] == ci[1] || ci[1] == ci[2] || ci[2] == ci[0])
				{
					continue;
				}

				for(k = 0; k < 3; k++)
				{
					index = ci[k];

					Com_Memcpy(indexes + indexesOfs, &index, sizeof(int));
					indexesOfs += sizeof(int);
				}
			}
		}		

		vboSurf->ibo[lod] = R_CreateIBO(va("staticMDMMesh_IBO_LOD_%f %i", flod, indexesNum / 3), indexes, indexesSize, VBO_USAGE_STATIC);
		vboSurf->ibo[lod]->indexesNum = indexesNum;

		ri.Free(indexes);

		if(vboTriangles->currentElements != surf->numTriangles)
		{
			ri.Printf(PRINT_WARNING, "Can't calculate LOD IBOs\n");
			break;
		}

		lod++;
	}
	while(lod < MD3_MAX_LODS);
	
	ri.Free(data);

	// megs
	/*
	   ri.Printf(PRINT_ALL, "md5 mesh data VBO size: %d.%02d MB\n", dataSize / (1024 * 1024),
	   (dataSize % (1024 * 1024)) * 100 / (1024 * 1024));
	   ri.Printf(PRINT_ALL, "md5 mesh tris VBO size: %d.%02d MB\n", indexesSize / (1024 * 1024),
	   (indexesSize % (1024 * 1024)) * 100 / (1024 * 1024));
	 */
}