Beispiel #1
0
/*
* Sys_GetPreferredLanguage
*/
const char *Sys_GetPreferredLanguage( void )
{
	static char lang[10];
	const char *locale;
	char *p;

	setlocale( LC_ALL, "" );
	locale = setlocale( LC_ALL, NULL );

	Q_strncpyz( lang, locale, sizeof( lang ) ); 

	setlocale( LC_ALL, "C" );

	p = strchr( lang, '.' );
	if( p ) { *p = '\0'; }

	if( !lang[0] ) {
		return APP_DEFAULT_LANGUAGE;
	}
	if( !Q_stricmp( lang, "C" ) ) {
		return APP_DEFAULT_LANGUAGE;
	}
	return Q_strlwr( lang );
}
Beispiel #2
0
void M_Menu_TV_ChannelAdd_f( void )
{
	int num, id;
	char *name, *realname, *address, *gametype, *mapname, *matchname;
	int numplayers, numspecs;
	tv_channel_t *prev, *next, *new_chan;

	if( trap_Cmd_Argc() < 5 )
		return;

	id = atoi( trap_Cmd_Argv( 1 ) );
	name = trap_Cmd_Argv( 2 );
	realname = trap_Cmd_Argv( 3 );
	address = trap_Cmd_Argv( 4 );
	numplayers = atoi( trap_Cmd_Argv( 5 ) );
	numspecs = atoi( trap_Cmd_Argv( 6 ) );
	gametype = trap_Cmd_Argv( 7 );
	mapname = trap_Cmd_Argv( 8 );
	matchname = trap_Cmd_Argv( 9 );
	if( id <= 0 || !name[0] )
		return;

	num = 0;
	prev = NULL;
	next = channels;
	while( next && next->id < id )
	{
		prev = next;
		next = next->next;
		num++;
	}
	if( next && next->id == id )
	{
		new_chan = next;
		next = new_chan->next;
	}
	else
	{
		new_chan = (tv_channel_t *)UI_Malloc( sizeof( tv_channel_t ) );
		if( num < scrollbar_curvalue )
			scrollbar_curvalue++;
	}
	if( prev )
	{
		prev->next = new_chan;
	}
	else
	{
		channels = new_chan;
	}
	new_chan->next = next;
	new_chan->id = id;
	Q_strncpyz( new_chan->name, name, sizeof( new_chan->name ) );
	Q_strncpyz( new_chan->realname, realname, sizeof( new_chan->realname ) );
	Q_strncpyz( new_chan->address, address, sizeof( new_chan->address ) );
	Q_strncpyz( new_chan->gametype, gametype, sizeof( new_chan->gametype ) );
	Q_strncpyz( new_chan->mapname, mapname, sizeof( new_chan->mapname ) );
	Q_strncpyz( new_chan->matchname, matchname, sizeof( new_chan->matchname ) );

	Q_strlwr( new_chan->gametype );
	Q_strlwr( new_chan->mapname );

	new_chan->numplayers = numplayers;
	new_chan->numspecs = numspecs;

	M_RefreshScrollWindowList();
}
Beispiel #3
0
/*
===============
CL_ParseFileList

Validate a path supplied by a filelist.
===============
*/
static void CL_CheckAndQueueDownload (char *path)
{
	size_t		length;
	char		*ext;
	qboolean	pak;
	qboolean	gameLocal;

	StripHighBits (path, 1);

	length = strlen(path);

	if (length >= MAX_QPATH)
		return;

	ext = strrchr (path, '.');

	if (!ext)
		return;

	ext++;

	if (!ext[0])
		return;

	Q_strlwr (ext);

	if ( !strcmp (ext, "pak") || !strcmp (ext, "pk3") )
	{
		Com_Printf ("NOTICE: Filelist is requesting a .pak file (%s)\n", path);
		pak = true;
	}
	else
		pak = false;

	if (!pak && strcmp (ext, "pcx") && strcmp (ext, "wal") && strcmp (ext, "wav") && strcmp (ext, "md2") &&
		strcmp (ext, "sp2") && strcmp (ext, "tga") && strcmp (ext, "png") && strcmp (ext, "jpg") &&
		strcmp (ext, "bsp") && strcmp (ext, "ent") && strcmp (ext, "txt") && strcmp (ext, "dm2") &&
		strcmp (ext, "loc"))
	{
		Com_Printf ("WARNING: Illegal file type '%s' in filelist.\n", MakePrintable(path, length));
		return;
	}

	if (path[0] == '@')
	{
		if (pak)
		{
			Com_Printf ("WARNING: @ prefix used on a pak file (%s) in filelist.\n", MakePrintable(path, length));
			return;
		}
		gameLocal = true;
		path++;
		length--;
	}
	else
		gameLocal = false;

	if (strstr (path, "..") || !IsValidChar (path[0]) || !IsValidChar (path[length-1]) || strstr(path, "//") ||
		strchr (path, '\\') || (!pak && !strchr (path, '/')) || (pak && strchr(path, '/')))
	{
		Com_Printf ("WARNING: Illegal path '%s' in filelist.\n", MakePrintable(path, length));
		return;
	}

	// by definition paks are game-local
	if (gameLocal || pak)
	{
		qboolean	exists;
		FILE		*f;
		char		gamePath[MAX_OSPATH];

		if (pak)
		{
			Com_sprintf (gamePath, sizeof(gamePath),"%s/%s",FS_Gamedir(), path);
			f = fopen (gamePath, "rb");
			if (!f)
			{
				exists = false;;
			}
			else
			{
				exists = true;
				fclose (f);
			}
		}
		else
		{
		//	exists = FS_ExistsInGameDir (path);
			exists = FS_LocalFileExists (path);
		}

		if (!exists)
		{
			if (CL_QueueHTTPDownload (path))
			{
				//paks get bumped to the top and HTTP switches to single downloading.
				//this prevents someone on 28k dialup trying to do both the main .pak
				//and referenced configstrings data at once.
				if (pak)
				{
					dlqueue_t	*q, *last;

					last = q = &cls.downloadQueue;

					while (q->next)
					{
						last = q;
						q = q->next;
					}

					last->next = NULL;
					q->next = cls.downloadQueue.next;
					cls.downloadQueue.next = q;
				}
			}
		}
	}
	else
	{
		CL_CheckOrDownloadFile (path);
	}
}
Beispiel #4
0
static qboolean R_LoadMD4( model_t *mod, void *buffer, const char *mod_name ) {
	int					i, j, k, lodindex;
	md4Header_t			*pinmodel, *md4;
    md4Frame_t			*frame;
	md4LOD_t			*lod;
	md4Surface_t		*surf;
	md4Triangle_t		*tri;
	md4Vertex_t			*v;
	int					version;
	int					size;
	shader_t			*sh;
	int					frameSize;

	pinmodel = (md4Header_t *)buffer;

	version = LittleLong (pinmodel->version);
	if (version != MD4_VERSION) {
		ri.Printf( PRINT_WARNING, "R_LoadMD4: %s has wrong version (%i should be %i)\n",
				 mod_name, version, MD4_VERSION);
		return qfalse;
	}

	mod->type = MOD_MD4;
	size = LittleLong(pinmodel->ofsEnd);
	mod->dataSize += size;
	md4 = mod->md4 = ri.Hunk_Alloc( size, h_low );

	memcpy(md4, buffer, size);

    LL(md4->ident);
    LL(md4->version);
    LL(md4->numFrames);
    LL(md4->numBones);
    LL(md4->numLODs);
    LL(md4->ofsFrames);
    LL(md4->ofsLODs);
    md4->ofsEnd = size;

	if ( md4->numFrames < 1 ) {
		ri.Printf( PRINT_WARNING, "R_LoadMD4: %s has no frames\n", mod_name );
		return qfalse;
	}

    // we don't need to swap tags in the renderer, they aren't used
    
	// swap all the frames
	frameSize = (size_t)( &((md4Frame_t *)0)->bones[ md4->numBones ] );
    for ( i = 0 ; i < md4->numFrames ; i++, frame++) {
	    frame = (md4Frame_t *) ( (byte *)md4 + md4->ofsFrames + i * frameSize );
    	frame->radius = LittleFloat( frame->radius );
        for ( j = 0 ; j < 3 ; j++ ) {
            frame->bounds[0][j] = LittleFloat( frame->bounds[0][j] );
            frame->bounds[1][j] = LittleFloat( frame->bounds[1][j] );
	    	frame->localOrigin[j] = LittleFloat( frame->localOrigin[j] );
        }
		for ( j = 0 ; j < md4->numBones * sizeof( md4Bone_t ) / 4 ; j++ ) {
			((float *)frame->bones)[j] = LittleFloat( ((float *)frame->bones)[j] );
		}
	}

	// swap all the LOD's
	lod = (md4LOD_t *) ( (byte *)md4 + md4->ofsLODs );
	for ( lodindex = 0 ; lodindex < md4->numLODs ; lodindex++ ) {

		// swap all the surfaces
		surf = (md4Surface_t *) ( (byte *)lod + lod->ofsSurfaces );
		for ( i = 0 ; i < lod->numSurfaces ; i++) {
			LL(surf->ident);
			LL(surf->numTriangles);
			LL(surf->ofsTriangles);
			LL(surf->numVerts);
			LL(surf->ofsVerts);
			LL(surf->ofsEnd);
			
			if ( surf->numVerts > SHADER_MAX_VERTEXES ) {
				ri.Error (ERR_DROP, "R_LoadMD3: %s has more than %i verts on a surface (%i)",
					mod_name, SHADER_MAX_VERTEXES, surf->numVerts );
			}
			if ( surf->numTriangles*3 > SHADER_MAX_INDEXES ) {
				ri.Error (ERR_DROP, "R_LoadMD3: %s has more than %i triangles on a surface (%i)",
					mod_name, SHADER_MAX_INDEXES / 3, surf->numTriangles );
			}

			// change to surface identifier
			surf->ident = SF_MD4;

			// lowercase the surface name so skin compares are faster
			Q_strlwr( surf->name );
		
			// register the shaders
			sh = R_FindShader( surf->shader, LIGHTMAP_NONE, qtrue );
			if ( sh->defaultShader ) {
				surf->shaderIndex = 0;
			} else {
				surf->shaderIndex = sh->index;
			}

			// swap all the triangles
			tri = (md4Triangle_t *) ( (byte *)surf + surf->ofsTriangles );
			for ( j = 0 ; j < surf->numTriangles ; j++, tri++ ) {
				LL(tri->indexes[0]);
				LL(tri->indexes[1]);
				LL(tri->indexes[2]);
			}

			// swap all the vertexes
			// FIXME
			// This makes TFC's skeletons work.  Shouldn't be necessary anymore, but left
			// in for reference.
			//v = (md4Vertex_t *) ( (byte *)surf + surf->ofsVerts + 12);
			v = (md4Vertex_t *) ( (byte *)surf + surf->ofsVerts);
			for ( j = 0 ; j < surf->numVerts ; j++ ) {
				v->normal[0] = LittleFloat( v->normal[0] );
				v->normal[1] = LittleFloat( v->normal[1] );
				v->normal[2] = LittleFloat( v->normal[2] );

				v->texCoords[0] = LittleFloat( v->texCoords[0] );
				v->texCoords[1] = LittleFloat( v->texCoords[1] );

				v->numWeights = LittleLong( v->numWeights );

				for ( k = 0 ; k < v->numWeights ; k++ ) {
					v->weights[k].boneIndex = LittleLong( v->weights[k].boneIndex );
					v->weights[k].boneWeight = LittleFloat( v->weights[k].boneWeight );
				   v->weights[k].offset[0] = LittleFloat( v->weights[k].offset[0] );
				   v->weights[k].offset[1] = LittleFloat( v->weights[k].offset[1] );
				   v->weights[k].offset[2] = LittleFloat( v->weights[k].offset[2] );
				}
				// FIXME
				// This makes TFC's skeletons work.  Shouldn't be necessary anymore, but left
				// in for reference.
				//v = (md4Vertex_t *)( ( byte * )&v->weights[v->numWeights] + 12 );
				v = (md4Vertex_t *)( ( byte * )&v->weights[v->numWeights]);
			}

			// find the next surface
			surf = (md4Surface_t *)( (byte *)surf + surf->ofsEnd );
		}

		// find the next LOD
		lod = (md4LOD_t *)( (byte *)lod + lod->ofsEnd );
	}

	return qtrue;
}
Beispiel #5
0
/*
=================
R_LoadMD3
=================
*/
static qboolean R_LoadMD3 (model_t *mod, int lod, void *buffer, const char *mod_name ) {
	int					i, j;
	md3Header_t			*pinmodel;
    md3Frame_t			*frame;
	md3Surface_t		*surf;
	md3Shader_t			*shader;
	md3Triangle_t		*tri;
	md3St_t				*st;
	md3XyzNormal_t		*xyz;
	md3Tag_t			*tag;
	int					version;
	int					size;

	pinmodel = (md3Header_t *)buffer;

	version = LittleLong (pinmodel->version);
	if (version != MD3_VERSION) {
		ri.Printf( PRINT_WARNING, "R_LoadMD3: %s has wrong version (%i should be %i)\n",
				 mod_name, version, MD3_VERSION);
		return qfalse;
	}

	mod->type = MOD_MESH;
	size = LittleLong(pinmodel->ofsEnd);
	mod->dataSize += size;
	mod->md3[lod] = ri.Hunk_Alloc( size, h_low );

	memcpy (mod->md3[lod], buffer, LittleLong(pinmodel->ofsEnd) );

    LL(mod->md3[lod]->ident);
    LL(mod->md3[lod]->version);
    LL(mod->md3[lod]->numFrames);
    LL(mod->md3[lod]->numTags);
    LL(mod->md3[lod]->numSurfaces);
    LL(mod->md3[lod]->ofsFrames);
    LL(mod->md3[lod]->ofsTags);
    LL(mod->md3[lod]->ofsSurfaces);
    LL(mod->md3[lod]->ofsEnd);

	if ( mod->md3[lod]->numFrames < 1 ) {
		ri.Printf( PRINT_WARNING, "R_LoadMD3: %s has no frames\n", mod_name );
		return qfalse;
	}
    
	// swap all the frames
    frame = (md3Frame_t *) ( (byte *)mod->md3[lod] + mod->md3[lod]->ofsFrames );
    for ( i = 0 ; i < mod->md3[lod]->numFrames ; i++, frame++) {
    	frame->radius = LittleFloat( frame->radius );
        for ( j = 0 ; j < 3 ; j++ ) {
            frame->bounds[0][j] = LittleFloat( frame->bounds[0][j] );
            frame->bounds[1][j] = LittleFloat( frame->bounds[1][j] );
	    	frame->localOrigin[j] = LittleFloat( frame->localOrigin[j] );
        }
	}

	// swap all the tags
    tag = (md3Tag_t *) ( (byte *)mod->md3[lod] + mod->md3[lod]->ofsTags );
    for ( i = 0 ; i < mod->md3[lod]->numTags * mod->md3[lod]->numFrames ; i++, tag++) {
        for ( j = 0 ; j < 3 ; j++ ) {
			tag->origin[j] = LittleFloat( tag->origin[j] );
			tag->axis[0][j] = LittleFloat( tag->axis[0][j] );
			tag->axis[1][j] = LittleFloat( tag->axis[1][j] );
			tag->axis[2][j] = LittleFloat( tag->axis[2][j] );
        }
	}

	// swap all the surfaces
	surf = (md3Surface_t *) ( (byte *)mod->md3[lod] + mod->md3[lod]->ofsSurfaces );
	for ( i = 0 ; i < mod->md3[lod]->numSurfaces ; i++) {

        LL(surf->ident);
        LL(surf->flags);
        LL(surf->numFrames);
        LL(surf->numShaders);
        LL(surf->numTriangles);
        LL(surf->ofsTriangles);
        LL(surf->numVerts);
        LL(surf->ofsShaders);
        LL(surf->ofsSt);
        LL(surf->ofsXyzNormals);
        LL(surf->ofsEnd);
		
		if ( surf->numVerts > SHADER_MAX_VERTEXES ) {
			ri.Error (ERR_DROP, "R_LoadMD3: %s has more than %i verts on a surface (%i)",
				mod_name, SHADER_MAX_VERTEXES, surf->numVerts );
		}
		if ( surf->numTriangles*3 > SHADER_MAX_INDEXES ) {
			ri.Error (ERR_DROP, "R_LoadMD3: %s has more than %i triangles on a surface (%i)",
				mod_name, SHADER_MAX_INDEXES / 3, surf->numTriangles );
		}
	
		// change to surface identifier
		surf->ident = SF_MD3;

		// lowercase the surface name so skin compares are faster
		Q_strlwr( surf->name );

		// strip off a trailing _1 or _2
		// this is a crutch for q3data being a mess
		j = strlen( surf->name );
		if ( j > 2 && surf->name[j-2] == '_' ) {
			surf->name[j-2] = 0;
		}

        // register the shaders
        shader = (md3Shader_t *) ( (byte *)surf + surf->ofsShaders );
        for ( j = 0 ; j < surf->numShaders ; j++, shader++ ) {
            shader_t	*sh;

            sh = R_FindShader( shader->name, LIGHTMAP_NONE, qtrue );
			if ( sh->defaultShader ) {
				shader->shaderIndex = 0;
			} else {
				shader->shaderIndex = sh->index;
			}
        }

		// swap all the triangles
		tri = (md3Triangle_t *) ( (byte *)surf + surf->ofsTriangles );
		for ( j = 0 ; j < surf->numTriangles ; j++, tri++ ) {
			LL(tri->indexes[0]);
			LL(tri->indexes[1]);
			LL(tri->indexes[2]);
		}

		// swap all the ST
        st = (md3St_t *) ( (byte *)surf + surf->ofsSt );
        for ( j = 0 ; j < surf->numVerts ; j++, st++ ) {
            st->st[0] = LittleFloat( st->st[0] );
            st->st[1] = LittleFloat( st->st[1] );
        }

		// swap all the XyzNormals
        xyz = (md3XyzNormal_t *) ( (byte *)surf + surf->ofsXyzNormals );
        for ( j = 0 ; j < surf->numVerts * surf->numFrames ; j++, xyz++ ) 
		{
            xyz->xyz[0] = LittleShort( xyz->xyz[0] );
            xyz->xyz[1] = LittleShort( xyz->xyz[1] );
            xyz->xyz[2] = LittleShort( xyz->xyz[2] );

            xyz->normal = LittleShort( xyz->normal );
        }


		// find the next surface
		surf = (md3Surface_t *)( (byte *)surf + surf->ofsEnd );
	}
    
	return qtrue;
}
Beispiel #6
0
/*
=================
R_LoadMDC
=================
*/
qboolean R_LoadMDC(model_t *mod, int lod, void *buffer, int bufferSize, const char *modName)
{
	int                i, j, k;
	mdcHeader_t        *mdcModel = ( mdcHeader_t * ) buffer;
	md3Frame_t         *mdcFrame;
	mdcSurface_t       *mdcSurf;
	md3Shader_t        *mdcShader;
	md3Triangle_t      *mdcTri;
	md3St_t            *mdcst;
	md3XyzNormal_t     *mdcxyz;
	mdcXyzCompressed_t *mdcxyzComp;
	mdcTag_t           *mdcTag;
	mdcTagName_t       *mdcTagName;
	mdvModel_t         *mdvModel;
	mdvFrame_t         *frame;
	mdvSurface_t       *surf; //, *surface; //unused
	srfTriangle_t      *tri;
	mdvXyz_t           *v;
	mdvSt_t            *st;
	mdvTag_t           *tag;
	mdvTagName_t       *tagName;
	short              *ps;
	int                version;
	int                size;

	version = LittleLong(mdcModel->version);

	if (version != MDC_VERSION)
	{
		Ren_Warning("R_LoadMD3: %s has wrong version (%i should be %i)\n", modName, version, MDC_VERSION);
		return qfalse;
	}

	mod->type      = MOD_MESH;
	size           = LittleLong(mdcModel->ofsEnd);
	mod->dataSize += size;
	mdvModel       = mod->mdv[lod] = ri.Hunk_Alloc(sizeof(mdvModel_t), h_low);

	LL(mdcModel->ident);
	LL(mdcModel->version);
	LL(mdcModel->numFrames);
	LL(mdcModel->numTags);
	LL(mdcModel->numSurfaces);
	LL(mdcModel->ofsFrames);
	LL(mdcModel->ofsTags);
	LL(mdcModel->ofsSurfaces);
	LL(mdcModel->ofsEnd);
	LL(mdcModel->ofsEnd);
	LL(mdcModel->flags);
	LL(mdcModel->numSkins);

	if (mdcModel->numFrames < 1)
	{
		Ren_Warning("R_LoadMDC: '%s' has no frames\n", modName);
		return qfalse;
	}

	// swap all the frames
	mdvModel->numFrames = mdcModel->numFrames;
	mdvModel->frames    = frame = ri.Hunk_Alloc(sizeof(*frame) * mdcModel->numFrames, h_low);

	mdcFrame = ( md3Frame_t * )(( byte * ) mdcModel + mdcModel->ofsFrames);

	for (i = 0; i < mdcModel->numFrames; i++, frame++, mdcFrame++)
	{
#if 1
		// ET HACK
		if (strstr(mod->name, "sherman") || strstr(mod->name, "mg42"))
		{
			frame->radius = 256;

			for (j = 0; j < 3; j++)
			{
				frame->bounds[0][j]   = 128;
				frame->bounds[1][j]   = -128;
				frame->localOrigin[j] = LittleFloat(mdcFrame->localOrigin[j]);
			}
		}
		else
#endif
		{
			frame->radius = LittleFloat(mdcFrame->radius);

			for (j = 0; j < 3; j++)
			{
				frame->bounds[0][j]   = LittleFloat(mdcFrame->bounds[0][j]);
				frame->bounds[1][j]   = LittleFloat(mdcFrame->bounds[1][j]);
				frame->localOrigin[j] = LittleFloat(mdcFrame->localOrigin[j]);
			}
		}
	}

	// swap all the tags
	mdvModel->numTags = mdcModel->numTags;
	mdvModel->tags    = tag = ri.Hunk_Alloc(sizeof(*tag) * (mdcModel->numTags * mdcModel->numFrames), h_low);

	mdcTag = ( mdcTag_t * )(( byte * ) mdcModel + mdcModel->ofsTags);

	for (i = 0; i < mdcModel->numTags * mdcModel->numFrames; i++, tag++, mdcTag++)
	{
		vec3_t angles;

		for (j = 0; j < 3; j++)
		{
			tag->origin[j] = ( float ) LittleShort(mdcTag->xyz[j]) * MD3_XYZ_SCALE;
			angles[j]      = ( float ) LittleShort(mdcTag->angles[j]) * MDC_TAG_ANGLE_SCALE;
		}

		AnglesToAxis(angles, tag->axis);
	}

	mdvModel->tagNames = tagName = ri.Hunk_Alloc(sizeof(*tagName) * (mdcModel->numTags), h_low);

	mdcTagName = ( mdcTagName_t * )(( byte * ) mdcModel + mdcModel->ofsTagNames);

	for (i = 0; i < mdcModel->numTags; i++, tagName++, mdcTagName++)
	{
		Q_strncpyz(tagName->name, mdcTagName->name, sizeof(tagName->name));
	}

	// swap all the surfaces
	mdvModel->numSurfaces = mdcModel->numSurfaces;
	mdvModel->surfaces    = surf = ri.Hunk_Alloc(sizeof(*surf) * mdcModel->numSurfaces, h_low);

	mdcSurf = ( mdcSurface_t * )(( byte * ) mdcModel + mdcModel->ofsSurfaces);

	for (i = 0; i < mdcModel->numSurfaces; i++)
	{
		LL(mdcSurf->ident);
		LL(mdcSurf->flags);
		LL(mdcSurf->numBaseFrames);
		LL(mdcSurf->numCompFrames);
		LL(mdcSurf->numShaders);
		LL(mdcSurf->numTriangles);
		LL(mdcSurf->ofsTriangles);
		LL(mdcSurf->numVerts);
		LL(mdcSurf->ofsShaders);
		LL(mdcSurf->ofsSt);
		LL(mdcSurf->ofsXyzNormals);
		LL(mdcSurf->ofsXyzNormals);
		LL(mdcSurf->ofsXyzCompressed);
		LL(mdcSurf->ofsFrameBaseFrames);
		LL(mdcSurf->ofsFrameCompFrames);
		LL(mdcSurf->ofsEnd);

		if (mdcSurf->numVerts > SHADER_MAX_VERTEXES)
		{
			Ren_Drop("R_LoadMDC: %s has more than %i verts on a surface (%i)",
			         modName, SHADER_MAX_VERTEXES, mdcSurf->numVerts);
		}

		if (mdcSurf->numTriangles > SHADER_MAX_TRIANGLES)
		{
			Ren_Drop("R_LoadMDC: %s has more than %i triangles on a surface (%i)",
			         modName, SHADER_MAX_TRIANGLES, mdcSurf->numTriangles);
		}

		// change to surface identifier
		surf->surfaceType = SF_MDV;

		// give pointer to model for Tess_SurfaceMDX
		surf->model = mdvModel;

		// copy surface name
		Q_strncpyz(surf->name, mdcSurf->name, sizeof(surf->name));

		// lowercase the surface name so skin compares are faster
		Q_strlwr(surf->name);

		// strip off a trailing _1 or _2
		// this is a crutch for q3data being a mess
		j = strlen(surf->name);

		if (j > 2 && surf->name[j - 2] == '_')
		{
			surf->name[j - 2] = 0;
		}

		// register the shaders

		/*
		   surf->numShaders = md3Surf->numShaders;
		   surf->shaders = shader = ri.Hunk_Alloc(sizeof(*shader) * md3Surf->numShaders, h_low);

		   md3Shader = (md3Shader_t *) ((byte *) md3Surf + md3Surf->ofsShaders);
		   for(j = 0; j < md3Surf->numShaders; j++, shader++, md3Shader++)
		   {
		   shader_t       *sh;

		   sh = R_FindShader(md3Shader->name, SHADER_3D_DYNAMIC, RSF_DEFAULT);
		   if(sh->defaultShader)
		   {
		   shader->shaderIndex = 0;
		   }
		   else
		   {
		   shader->shaderIndex = sh->index;
		   }
		   }
		 */

		// only consider the first shader
		mdcShader    = ( md3Shader_t * )(( byte * ) mdcSurf + mdcSurf->ofsShaders);
		surf->shader = R_FindShader(mdcShader->name, SHADER_3D_DYNAMIC, qtrue);

		// swap all the triangles
		surf->numTriangles = mdcSurf->numTriangles;
		surf->triangles    = tri = ri.Hunk_Alloc(sizeof(*tri) * mdcSurf->numTriangles, h_low);

		mdcTri = ( md3Triangle_t * )(( byte * ) mdcSurf + mdcSurf->ofsTriangles);

		for (j = 0; j < mdcSurf->numTriangles; j++, tri++, mdcTri++)
		{
			tri->indexes[0] = LittleLong(mdcTri->indexes[0]);
			tri->indexes[1] = LittleLong(mdcTri->indexes[1]);
			tri->indexes[2] = LittleLong(mdcTri->indexes[2]);
		}

		// swap all the XyzNormals
		mdcxyz = ( md3XyzNormal_t * )(( byte * ) mdcSurf + mdcSurf->ofsXyzNormals);

		for (j = 0; j < mdcSurf->numVerts * mdcSurf->numBaseFrames; j++, mdcxyz++)
		{
			mdcxyz->xyz[0] = LittleShort(mdcxyz->xyz[0]);
			mdcxyz->xyz[1] = LittleShort(mdcxyz->xyz[1]);
			mdcxyz->xyz[2] = LittleShort(mdcxyz->xyz[2]);

			mdcxyz->normal = LittleShort(mdcxyz->normal);
		}

		// swap all the XyzCompressed
		mdcxyzComp = ( mdcXyzCompressed_t * )(( byte * ) mdcSurf + mdcSurf->ofsXyzCompressed);

		for (j = 0; j < mdcSurf->numVerts * mdcSurf->numCompFrames; j++, mdcxyzComp++)
		{
			LL(mdcxyzComp->ofsVec);
		}

		// swap the frameBaseFrames
		ps = ( short * )(( byte * ) mdcSurf + mdcSurf->ofsFrameBaseFrames);

		for (j = 0; j < mdcModel->numFrames; j++, ps++)
		{
			*ps = LittleShort(*ps);
		}

		// swap the frameCompFrames
		ps = ( short * )(( byte * ) mdcSurf + mdcSurf->ofsFrameCompFrames);

		for (j = 0; j < mdcModel->numFrames; j++, ps++)
		{
			*ps = LittleShort(*ps);
		}

		surf->numVerts = mdcSurf->numVerts;
		surf->verts    = v = ri.Hunk_Alloc(sizeof(*v) * (mdcSurf->numVerts * mdcModel->numFrames), h_low);

		for (j = 0; j < mdcModel->numFrames; j++)
		{
			int baseFrame;
			int compFrame = 0;

			baseFrame = ( int ) *(( short * )(( byte * ) mdcSurf + mdcSurf->ofsFrameBaseFrames) + j);

			mdcxyz = ( md3XyzNormal_t * )(( byte * ) mdcSurf + mdcSurf->ofsXyzNormals + baseFrame * mdcSurf->numVerts * sizeof(md3XyzNormal_t));

			if (mdcSurf->numCompFrames > 0)
			{
				compFrame = ( int ) *(( short * )(( byte * ) mdcSurf + mdcSurf->ofsFrameCompFrames) + j);

				if (compFrame >= 0)
				{
					mdcxyzComp = ( mdcXyzCompressed_t * )(( byte * ) mdcSurf + mdcSurf->ofsXyzCompressed + compFrame * mdcSurf->numVerts * sizeof(mdcXyzCompressed_t));
				}
			}

			for (k = 0; k < mdcSurf->numVerts; k++, v++, mdcxyz++)
			{
				v->xyz[0] = LittleShort(mdcxyz->xyz[0]) * MD3_XYZ_SCALE;
				v->xyz[1] = LittleShort(mdcxyz->xyz[1]) * MD3_XYZ_SCALE;
				v->xyz[2] = LittleShort(mdcxyz->xyz[2]) * MD3_XYZ_SCALE;

				if (mdcSurf->numCompFrames > 0 && compFrame >= 0)
				{
					vec3_t ofsVec;

					R_MDC_DecodeXyzCompressed2(LittleShort(mdcxyzComp->ofsVec), ofsVec);
					VectorAdd(v->xyz, ofsVec, v->xyz);

					mdcxyzComp++;
				}
			}
		}

		// swap all the ST
		surf->st = st = ri.Hunk_Alloc(sizeof(*st) * mdcSurf->numVerts, h_low);

		mdcst = ( md3St_t * )(( byte * ) mdcSurf + mdcSurf->ofsSt);

		for (j = 0; j < mdcSurf->numVerts; j++, mdcst++, st++)
		{
			st->st[0] = LittleFloat(mdcst->st[0]);
			st->st[1] = LittleFloat(mdcst->st[1]);
		}

		// find the next surface
		mdcSurf = ( mdcSurface_t * )(( byte * ) mdcSurf + mdcSurf->ofsEnd);
		surf++;
	}

#if 1
	// create VBO surfaces from md3 surfaces
	{
		mdvNormTanBi_t *vertexes;
		mdvNormTanBi_t *vert;

		growList_t      vboSurfaces;
		srfVBOMDVMesh_t *vboSurf;

		byte *data;
		int  dataSize;
		int  dataOfs;

		vec4_t tmp;

		GLuint ofsTexCoords;
		GLuint ofsTangents;
		GLuint ofsBinormals;
		GLuint ofsNormals;

		GLuint sizeXYZ       = 0;
		GLuint sizeTangents  = 0;
		GLuint sizeBinormals = 0;
		GLuint sizeNormals   = 0;

		int vertexesNum;
		int f;

		Com_InitGrowList(&vboSurfaces, 10);

		for (i = 0, surf = mdvModel->surfaces; i < mdvModel->numSurfaces; i++, surf++)
		{
			//allocate temp memory for vertex data
			vertexes = (mdvNormTanBi_t *)ri.Hunk_AllocateTempMemory(sizeof(*vertexes) * surf->numVerts * mdvModel->numFrames);

			// calc tangent spaces
			{
				const float *v0, *v1, *v2;
				const float *t0, *t1, *t2;
				vec3_t      tangent;
				vec3_t      binormal;
				vec3_t      normal;

				for (j = 0, vert = vertexes; j < (surf->numVerts * mdvModel->numFrames); j++, vert++)
				{
					VectorClear(vert->tangent);
					VectorClear(vert->binormal);
					VectorClear(vert->normal);
				}

				for (f = 0; f < mdvModel->numFrames; f++)
				{
					for (j = 0, tri = surf->triangles; j < surf->numTriangles; j++, tri++)
					{
						v0 = surf->verts[surf->numVerts * f + tri->indexes[0]].xyz;
						v1 = surf->verts[surf->numVerts * f + tri->indexes[1]].xyz;
						v2 = surf->verts[surf->numVerts * f + tri->indexes[2]].xyz;

						t0 = surf->st[tri->indexes[0]].st;
						t1 = surf->st[tri->indexes[1]].st;
						t2 = surf->st[tri->indexes[2]].st;

#if 1
						R_CalcTangentSpace(tangent, binormal, normal, v0, v1, v2, t0, t1, t2);
#else
						R_CalcNormalForTriangle(normal, v0, v1, v2);
						R_CalcTangentsForTriangle(tangent, binormal, v0, v1, v2, t0, t1, t2);
#endif

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

							v = vertexes[surf->numVerts * f + tri->indexes[k]].tangent;
							VectorAdd(v, tangent, v);

							v = vertexes[surf->numVerts * f + tri->indexes[k]].binormal;
							VectorAdd(v, binormal, v);

							v = vertexes[surf->numVerts * f + tri->indexes[k]].normal;
							VectorAdd(v, normal, v);
						}
					}
				}

				for (j = 0, vert = vertexes; j < (surf->numVerts * mdvModel->numFrames); j++, vert++)
				{
					VectorNormalize(vert->tangent);
					VectorNormalize(vert->binormal);
					VectorNormalize(vert->normal);
				}
			}

			//Ren_Print("...calculating MDC mesh VBOs ( '%s', %i verts %i tris )\n", surf->name, surf->numVerts, surf->numTriangles);

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

			vboSurf->surfaceType = SF_VBO_MDVMESH;
			vboSurf->mdvModel    = mdvModel;
			vboSurf->mdvSurface  = surf;
			vboSurf->numIndexes  = surf->numTriangles * 3;
			vboSurf->numVerts    = surf->numVerts;

			/*
			vboSurf->vbo = R_CreateVBO2(va("staticWorldMesh_vertices %i", vboSurfaces.currentElements), numVerts, optimizedVerts,
			                                                   ATTR_POSITION | ATTR_TEXCOORD | ATTR_LIGHTCOORD | ATTR_TANGENT | ATTR_BINORMAL | ATTR_NORMAL
			                                                   | ATTR_COLOR);
			                                                   */

			vboSurf->ibo = R_CreateIBO2(va("staticMDCMesh_IBO %s", surf->name), surf->numTriangles, surf->triangles, VBO_USAGE_STATIC);

			// create VBO
			vertexesNum = surf->numVerts;

			dataSize = (surf->numVerts * mdvModel->numFrames * sizeof(vec4_t) * 4) +      // xyz, tangent, binormal, normal
			           (surf->numVerts * sizeof(vec4_t));      // texcoords
			data    = ri.Hunk_AllocateTempMemory(dataSize);
			dataOfs = 0;

			// feed vertex XYZ
			for (f = 0; f < mdvModel->numFrames; f++)
			{
				for (j = 0; j < vertexesNum; j++)
				{
					for (k = 0; k < 3; k++)
					{
						tmp[k] = surf->verts[f * vertexesNum + j].xyz[k];
					}

					tmp[3] = 1;
					Com_Memcpy(data + dataOfs, ( vec_t * ) tmp, sizeof(vec4_t));
					dataOfs += sizeof(vec4_t);
				}

				if (f == 0)
				{
					sizeXYZ = dataOfs;
				}
			}

			// feed vertex texcoords
			ofsTexCoords = dataOfs;

			for (j = 0; j < vertexesNum; j++)
			{
				for (k = 0; k < 2; k++)
				{
					tmp[k] = surf->st[j].st[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 (f = 0; f < mdvModel->numFrames; f++)
			{
				for (j = 0; j < vertexesNum; j++)
				{
					for (k = 0; k < 3; k++)
					{
						tmp[k] = vertexes[f * vertexesNum + j].tangent[k];
					}

					tmp[3] = 1;
					Com_Memcpy(data + dataOfs, ( vec_t * ) tmp, sizeof(vec4_t));
					dataOfs += sizeof(vec4_t);
				}

				if (f == 0)
				{
					sizeTangents = dataOfs - ofsTangents;
				}
			}

			// feed vertex binormals
			ofsBinormals = dataOfs;

			for (f = 0; f < mdvModel->numFrames; f++)
			{
				for (j = 0; j < vertexesNum; j++)
				{
					for (k = 0; k < 3; k++)
					{
						tmp[k] = vertexes[f * vertexesNum + j].binormal[k];
					}

					tmp[3] = 1;
					Com_Memcpy(data + dataOfs, ( vec_t * ) tmp, sizeof(vec4_t));
					dataOfs += sizeof(vec4_t);
				}

				if (f == 0)
				{
					sizeBinormals = dataOfs - ofsBinormals;
				}
			}

			// feed vertex normals
			ofsNormals = dataOfs;

			for (f = 0; f < mdvModel->numFrames; f++)
			{
				for (j = 0; j < vertexesNum; j++)
				{
					for (k = 0; k < 3; k++)
					{
						tmp[k] = vertexes[f * vertexesNum + j].normal[k];
					}

					tmp[3] = 1;
					Com_Memcpy(data + dataOfs, ( vec_t * ) tmp, sizeof(vec4_t));
					dataOfs += sizeof(vec4_t);
				}

				if (f == 0)
				{
					sizeNormals = dataOfs - ofsNormals;
				}
			}

			vboSurf->vbo                 = R_CreateVBO(va("staticMDCMesh_VBO '%s'", surf->name), 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->sizeXYZ       = sizeXYZ;
			vboSurf->vbo->sizeTangents  = sizeTangents;
			vboSurf->vbo->sizeBinormals = sizeBinormals;
			vboSurf->vbo->sizeNormals   = sizeNormals;

			ri.Hunk_FreeTempMemory(data);
			ri.Hunk_FreeTempMemory(vertexes);
		}

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

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

		Com_DestroyGrowList(&vboSurfaces);
	}
#endif

	return qtrue;
}
/*
============
AnimParseAnimConfig

  returns qfalse if error, qtrue otherwise
============
*/
static qboolean AnimParseAnimConfig( playerInfo_t *animModelInfo, const char *filename, const char *input ) {
	char    *text_p, *token;
	animation_t *animations;
//	headAnimation_t *headAnims;
	int i, fps, skip = -1;

//	if (!weaponStringsInited) {
//		BG_InitWeaponStrings();
//	}

//	globalFilename = (char *)filename;

	animations = animModelInfo->animations;
	animModelInfo->numAnimations = 0;
//	headAnims = animModelInfo->headAnims;

	text_p = (char *)input;
	COM_BeginParseSession( "AnimParseAnimConfig" );

	animModelInfo->footsteps = FOOTSTEP_NORMAL;
	VectorClear( animModelInfo->headOffset );
	animModelInfo->gender = GENDER_MALE;
	animModelInfo->isSkeletal = qfalse;
	animModelInfo->version = 0;

	// read optional parameters
	while ( 1 ) {
		token = COM_Parse( &text_p );
		if ( !token ) {
			break;
		}
		if ( !Q_stricmp( token, "footsteps" ) ) {
			token = COM_Parse( &text_p );
			if ( !token ) {
				break;
			}
			if ( !Q_stricmp( token, "default" ) || !Q_stricmp( token, "normal" ) ) {
				animModelInfo->footsteps = FOOTSTEP_NORMAL;
			} else if ( !Q_stricmp( token, "boot" ) ) {
				animModelInfo->footsteps = FOOTSTEP_BOOT;
			} else if ( !Q_stricmp( token, "flesh" ) ) {
				animModelInfo->footsteps = FOOTSTEP_FLESH;
			} else if ( !Q_stricmp( token, "mech" ) ) {
				animModelInfo->footsteps = FOOTSTEP_MECH;
			} else if ( !Q_stricmp( token, "energy" ) ) {
				animModelInfo->footsteps = FOOTSTEP_ENERGY;
			} else {
//				BG_AnimParseError( "Bad footsteps parm '%s'\n", token );
			}
			continue;
		} else if ( !Q_stricmp( token, "headoffset" ) ) {
			for ( i = 0 ; i < 3 ; i++ ) {
				token = COM_Parse( &text_p );
				if ( !token ) {
					break;
				}
				animModelInfo->headOffset[i] = atof( token );
			}
			continue;
		} else if ( !Q_stricmp( token, "sex" ) ) {
			token = COM_Parse( &text_p );
			if ( !token ) {
				break;
			}
			if ( token[0] == 'f' || token[0] == 'F' ) {
				animModelInfo->gender = GENDER_FEMALE;
			} else if ( token[0] == 'n' || token[0] == 'N' ) {
				animModelInfo->gender = GENDER_NEUTER;
			} else {
				animModelInfo->gender = GENDER_MALE;
			}
			continue;
		} else if ( !Q_stricmp( token, "version" ) ) {
			token = COM_Parse( &text_p );
			if ( !token ) {
				break;
			}
			animModelInfo->version = atoi( token );
			continue;
		} else if ( !Q_stricmp( token, "skeletal" ) ) {
			animModelInfo->isSkeletal = qtrue;
			continue;
		}

		if ( animModelInfo->version < 2 ) {
			// if it is a number, start parsing animations
			if ( Q_isnumeric( token[0] ) ) {
				text_p -= strlen( token );    // unget the token
				break;
			}
		}

		// STARTANIMS marks the start of the animations
		if ( !Q_stricmp( token, "STARTANIMS" ) ) {
			break;
		}
//		BG_AnimParseError( "unknown token '%s'", token );
	}

	// read information for each frame
	for ( i = 0 ; ( animModelInfo->version > 1 ) || ( i < MAX_ANIMATIONS ) ; i++ ) {

		token = COM_Parse( &text_p );
		if ( !token ) {
			break;
		}

		if ( animModelInfo->version > 1 ) {   // includes animation names at start of each line

			if ( !Q_stricmp( token, "ENDANIMS" ) ) {   // end of animations
				break;
			}

			Q_strncpyz( animations[i].name, token, sizeof( animations[i].name ) );
			// convert to all lower case
			Q_strlwr( animations[i].name );
			//
			token = COM_ParseExt( &text_p, qfalse );
			if ( !token || !token[0] ) {
//				BG_AnimParseError( "end of file without ENDANIMS" );
				break;
			}
		} else {
			// just set it to the equivalent animStrings[]
			Q_strncpyz( animations[i].name, animStrings[i], sizeof( animations[i].name ) );
			// convert to all lower case
			Q_strlwr( animations[i].name );
		}

		animations[i].firstFrame = atoi( token );

		if ( !animModelInfo->isSkeletal ) { // skeletal models dont require adjustment

			// leg only frames are adjusted to not count the upper body only frames
			if ( i == LEGS_WALKCR ) {
				skip = animations[LEGS_WALKCR].firstFrame - animations[TORSO_GESTURE].firstFrame;
			}
			if ( i >= LEGS_WALKCR ) {
				animations[i].firstFrame -= skip;
			}

		}

		token = COM_ParseExt( &text_p, qfalse );
		if ( !token || !token[0] ) {
//			BG_AnimParseError( "end of file without ENDANIMS" );
			break;
		}
		animations[i].numFrames = atoi( token );

		token = COM_ParseExt( &text_p, qfalse );
		if ( !token || !token[0] ) {
//			BG_AnimParseError( "end of file without ENDANIMS: line %i" );
			break;
		}
		animations[i].loopFrames = atoi( token );

		token = COM_ParseExt( &text_p, qfalse );
		if ( !token || !token[0] ) {
//			BG_AnimParseError( "end of file without ENDANIMS: line %i" );
			break;
		}
		fps = atof( token );
		if ( fps == 0 ) {
			fps = 1;
		}
		animations[i].frameLerp = 1000 / fps;
		animations[i].initialLerp = 1000 / fps;

		// movespeed
		token = COM_ParseExt( &text_p, qfalse );
		if ( !token || !token[0] ) {
//			BG_AnimParseError( "end of file without ENDANIMS" );
			break;
		}
		animations[i].moveSpeed = atoi( token );

		// animation blending
		token = COM_ParseExt( &text_p, qfalse );    // must be on same line
		if ( !token ) {
			animations[i].animBlend = 0;
		} else {
			animations[i].animBlend = atoi( token );
		}

		// calculate the duration
		animations[i].duration = animations[i].initialLerp
								 + animations[i].frameLerp * animations[i].numFrames
								 + animations[i].animBlend;

		// get the nameHash
		animations[i].nameHash = BG_StringHashValue( animations[i].name );

		if ( !Q_strncmp( animations[i].name, "climb", 5 ) ) {
			animations[i].flags |= ANIMFL_LADDERANIM;
		}
		if ( strstr( animations[i].name, "firing" ) ) {
			animations[i].flags |= ANIMFL_FIRINGANIM;
			animations[i].initialLerp = 40;
		}

	}

	animModelInfo->numAnimations = i;

	if ( animModelInfo->version < 2 && i != MAX_ANIMATIONS ) {
//		BG_AnimParseError( "Incorrect number of animations" );
		return qfalse;
	}

#if 0
	// check for head anims
	token = COM_Parse( &text_p );
	if ( token && token[0] ) {
		if ( animModelInfo->version < 2 || !Q_stricmp( token, "HEADFRAMES" ) ) {

			// read information for each head frame
			for ( i = 0 ; i < MAX_HEAD_ANIMS ; i++ ) {

				token = COM_Parse( &text_p );
				if ( !token || !token[0] ) {
					break;
				}

				if ( animModelInfo->version > 1 ) {   // includes animation names at start of each line
					// just throw this information away, not required for head
					token = COM_ParseExt( &text_p, qfalse );
					if ( !token || !token[0] ) {
						break;
					}
				}

				if ( !i ) {
					skip = atoi( token );
				}

				headAnims[i].firstFrame = atoi( token );
				// modify according to last frame of the main animations, since the head is totally seperate
				headAnims[i].firstFrame -= animations[MAX_ANIMATIONS - 1].firstFrame + animations[MAX_ANIMATIONS - 1].numFrames + skip;

				token = COM_ParseExt( &text_p, qfalse );
				if ( !token || !token[0] ) {
					break;
				}
				headAnims[i].numFrames = atoi( token );

				// skip the movespeed
				token = COM_ParseExt( &text_p, qfalse );
			}

//			animModelInfo->numHeadAnims = i;

			if ( i != MAX_HEAD_ANIMS ) {
//				BG_AnimParseError( "Incorrect number of head frames" );
				return qfalse;
			}

		}
	}
#endif

	return qtrue;
}
Beispiel #8
0
// Unfortunately the dedicated server also hates shader loading. So we need an alternate of this func.
//
void *RE_RegisterServerModels_Malloc(int iSize, void *pvDiskBufferIfJustLoaded, const char *psModelFileName, qboolean *pqbAlreadyFound, memtag_t eTag)
{
	char sModelName[MAX_QPATH];

	assert(CachedModels);

	Q_strncpyz(sModelName,psModelFileName,sizeof(sModelName));
	Q_strlwr  (sModelName);

	CachedEndianedModelBinary_t &ModelBin = (*CachedModels)[sModelName];

	if (ModelBin.pModelDiskImage == NULL)
	{
		// new, instead of doing a Z_Malloc and assigning that we just morph the disk buffer alloc
		//	then don't thrown it away on return - cuts down on mem overhead
		//
		// ... groan, but not if doing a limb hierarchy creation (some VV stuff?), in which case it's NULL
		//
		if ( pvDiskBufferIfJustLoaded )
		{
			Z_MorphMallocTag( pvDiskBufferIfJustLoaded, eTag );
		}
		else
		{
			pvDiskBufferIfJustLoaded =  Z_Malloc(iSize,eTag, qfalse );
		}

		ModelBin.pModelDiskImage	= pvDiskBufferIfJustLoaded;
		ModelBin.iAllocSize			= iSize;

		int iCheckSum;
		if (ri->FS_FileIsInPAK(sModelName, &iCheckSum) == 1)
		{
			ModelBin.iPAKFileCheckSum = iCheckSum;	// else ModelBin's constructor will leave it as -1
		}

		*pqbAlreadyFound = qfalse;
	}
	else
	{
		// if we already had this model entry, then re-register all the shaders it wanted...
		//
		/*
		int iEntries = ModelBin.ShaderRegisterData.size();
		for (int i=0; i<iEntries; i++)
		{
			int iShaderNameOffset	= ModelBin.ShaderRegisterData[i].first;
			int iShaderPokeOffset	= ModelBin.ShaderRegisterData[i].second;

			char *psShaderName		=		  &((char*)ModelBin.pModelDiskImage)[iShaderNameOffset];
			int  *piShaderPokePtr	= (int *) &((char*)ModelBin.pModelDiskImage)[iShaderPokeOffset];

			shader_t *sh = R_FindShader( psShaderName, lightmapsNone, stylesDefault, qtrue );

			if ( sh->defaultShader )
			{
				*piShaderPokePtr = 0;
			} else {
				*piShaderPokePtr = sh->index;
			}
		}
		*/
		//No. Bad.
		*pqbAlreadyFound = qtrue;	// tell caller not to re-Endian or re-Shader this binary
	}

	ModelBin.iLastLevelUsedOn = RE_RegisterMedia_GetLevel();

	return ModelBin.pModelDiskImage;
}
Beispiel #9
0
static void SV_AntiCheat_ParseHashLine (char *line, int line_number, const char *filename)
{
	filehash_t	*hashes;
	int			i;
	int			flags;
	char		*p, *hash;

	if (line[0] == '!')
	{
		strncpy (anticheat_hashlist_name, line + 1, sizeof(anticheat_hashlist_name)-1);
		ExpandNewLines (anticheat_hashlist_name);
		return;
	}

	p = strchr (line, '\t');
	if (!p)
	{
		Com_Printf ("ANTICHEAT WARNING: Malformed line %d '%s' in %s\n", LOG_WARNING|LOG_ANTICHEAT|LOG_SERVER, line_number, line, filename);
		return;
	}

	p[0] = 0;
	p++;

	hash = p;

	p = strchr (hash, '\t');
	if (p)
	{
		p[0] = 0;
		p++;
	}

	if (strlen (hash) != 40)
	{
		Com_Printf ("ANTICHEAT WARNING: Malformed hash '%s' in %s on line %d\n", LOG_WARNING|LOG_ANTICHEAT|LOG_SERVER, hash, filename, line_number);
		return;
	}

	for (i = 0; i < 40; i++)
	{
		if (!isxdigit (hash[i]))
		{
			Com_Printf ("ANTICHEAT WARNING: Malformed hash '%s' in %s on line %d\n", LOG_WARNING|LOG_ANTICHEAT|LOG_SERVER, hash, filename, line_number);
			return;
		}
	}

	if (strlen (line) >= MAX_QPATH || strchr (line, '\\') || !isalnum(line[0]))
	{
		Com_Printf ("ANTICHEAT WARNING: Malformed quake path '%s' in %s on line %d\n", LOG_WARNING|LOG_ANTICHEAT|LOG_SERVER, line, filename, line_number);
		return;
	}

	Q_strlwr (line);

	flags = 0;

	if (p && p[0])
	{
		if (strstr (p, "required"))
			flags |= ACH_REQUIRED;
		if (strstr (p, "negative"))
			flags |= ACH_NEGATIVE;
	}

	hashes = &fileHashes;

	while (hashes->next)
		hashes = hashes->next;

	hashes->next = Z_TagMalloc (sizeof(*hashes), TAGMALLOC_ANTICHEAT);
	hashes = hashes->next;
	hashes->next = NULL;

	for (i = 0; i < 20; i++)
		hashes->hash[i] = HexToRaw (hash + i*2);
	
	hashes->flags = flags;

	strcpy (hashes->quakePath, line);
	antiCheatNumFileHashes++;
}
Beispiel #10
0
// Validate a path supplied by a filelist.
static void check_and_queue_download(char *path)
{
    size_t      len;
    char        *ext;
    dltype_t    type;
    unsigned    flags;
    int         valid;

    len = strlen(path);
    if (len >= MAX_QPATH)
        return;

    ext = strrchr(path, '.');
    if (!ext)
        return;

    ext++;
    if (!ext[0])
        return;

    Q_strlwr(ext);

    if (!strcmp(ext, "pak") || !strcmp(ext, "pkz")) {
        Com_Printf("[HTTP] Filelist is requesting a .%s file '%s'\n", ext, path);
        type = DL_PAK;
    } else {
        type = DL_OTHER;
        if (!CL_CheckDownloadExtension(ext)) {
            Com_WPrintf("[HTTP] Illegal file type '%s' in filelist.\n", path);
            return;
        }
    }

    if (path[0] == '@') {
        if (type == DL_PAK) {
            Com_WPrintf("[HTTP] '@' prefix used on a pak file '%s' in filelist.\n", path);
            return;
        }
        flags = FS_PATH_GAME;
        path++;
        len--;
    } else if (type == DL_PAK) {
        //by definition paks are game-local
        flags = FS_PATH_GAME | FS_TYPE_REAL;
    } else {
        flags = 0;
    }

    len = FS_NormalizePath(path, path);
    if (len == 0)
        return;

    valid = FS_ValidatePath(path);

    if (valid == PATH_INVALID ||
        !Q_ispath(path[0]) ||
        !Q_ispath(path[len - 1]) ||
        strstr(path, "..") ||
        (type == DL_OTHER && !strchr(path, '/')) ||
        (type == DL_PAK && strchr(path, '/'))) {
        Com_WPrintf("[HTTP] Illegal path '%s' in filelist.\n", path);
        return;
    }

    if (FS_FileExistsEx(path, flags))
        return;

    if (valid == PATH_MIXED_CASE)
        Q_strlwr(path);

    if (CL_IgnoreDownload(path))
        return;

    CL_QueueDownload(path, type);
}
Beispiel #11
0
qboolean BG_LoadTraceMap(char *rawmapname, vec2_t world_mins, vec2_t world_maxs)
{
    int          i, j;
    fileHandle_t f;
    byte         data, datablock[TRACEMAP_SIZE][4];
    int          sky_min, sky_max;
    int          ground_min, ground_max;
    int          skyground_min, skyground_max;
    float        scalefactor;
    //int startTime = trap_Milliseconds();

    ground_min    = ground_max = MIN_WORLD_HEIGHT;
    skyground_min = skyground_max = MAX_WORLD_HEIGHT;
    sky_min       = sky_max = MAX_WORLD_HEIGHT;

    if (trap_FS_FOpenFile(va("maps/%s_tracemap.tga", Q_strlwr(rawmapname)), &f, FS_READ) >= 0)
    {
        // skip over header
        for (i = 0; i < 18; i++)
        {
            trap_FS_Read(&data, 1, f);
        }

        for (i = 0; i < TRACEMAP_SIZE; i++)
        {
            trap_FS_Read(&datablock, sizeof(datablock), f);    // TRACEMAP_SIZE * { b g r a }

            for (j = 0; j < TRACEMAP_SIZE; j++)
            {
                if (i == 0 && j < 6)
                {
                    // abuse first six pixels for our extended data
                    switch (j)
                    {
                    case 0:    ground_min    = datablock[j][0] | (datablock[j][1] << 8) | (datablock[j][2] << 16) | (datablock[j][3] << 24); break;
                    case 1:    ground_max    = datablock[j][0] | (datablock[j][1] << 8) | (datablock[j][2] << 16) | (datablock[j][3] << 24); break;
                    case 2:    skyground_min = datablock[j][0] | (datablock[j][1] << 8) | (datablock[j][2] << 16) | (datablock[j][3] << 24); break;
                    case 3:    skyground_max = datablock[j][0] | (datablock[j][1] << 8) | (datablock[j][2] << 16) | (datablock[j][3] << 24); break;
                    case 4:    sky_min       = datablock[j][0] | (datablock[j][1] << 8) | (datablock[j][2] << 16) | (datablock[j][3] << 24); break;
                    case 5:    sky_max       = datablock[j][0] | (datablock[j][1] << 8) | (datablock[j][2] << 16) | (datablock[j][3] << 24); break;
                    }
                    tracemap.sky[TRACEMAP_SIZE - 1 - i][j]       = MAX_WORLD_HEIGHT;
                    tracemap.skyground[TRACEMAP_SIZE - 1 - i][j] = MAX_WORLD_HEIGHT;
                    tracemap.ground[TRACEMAP_SIZE - 1 - i][j]    = MIN_WORLD_HEIGHT;
                    continue;
                }

                tracemap.sky[TRACEMAP_SIZE - 1 - i][j] = (float)datablock[j][0];    // FIXME: swap
                if (tracemap.sky[TRACEMAP_SIZE - 1 - i][j] == 0)
                {
                    tracemap.sky[TRACEMAP_SIZE - 1 - i][j] = MAX_WORLD_HEIGHT;
                }

                tracemap.skyground[TRACEMAP_SIZE - 1 - i][j] = (float)datablock[j][1];    // FIXME: swap
                if (tracemap.skyground[TRACEMAP_SIZE - 1 - i][j] == 0)
                {
                    tracemap.skyground[TRACEMAP_SIZE - 1 - i][j] = MAX_WORLD_HEIGHT;
                }

                tracemap.ground[TRACEMAP_SIZE - 1 - i][j] = (float)datablock[j][2];    // FIXME: swap
                if (tracemap.ground[TRACEMAP_SIZE - 1 - i][j] == 0)
                {
                    tracemap.ground[TRACEMAP_SIZE - 1 - i][j] = MIN_WORLD_HEIGHT;
                }

                if (datablock[j][3] == 0)
                {
                    // just in case
                    tracemap.skyground[TRACEMAP_SIZE - 1 - i][j] = MAX_WORLD_HEIGHT;
                    tracemap.ground[TRACEMAP_SIZE - 1 - i][j]    = MIN_WORLD_HEIGHT;
                }
            }
        }

        trap_FS_FCloseFile(f);

        // Ground
        // calculate scalefactor
        if (ground_max - ground_min == 0)
        {
            scalefactor = 1.f;
        }
        else
        {
            // rain - scalefactor 254 to compensate for broken etmain behavior
            scalefactor = 254.f / (ground_max - ground_min);
        }

        // scale properly
        for (i = 0; i < TRACEMAP_SIZE; i++)
        {
            for (j = 0; j < TRACEMAP_SIZE; j++)
            {
                if (tracemap.ground[i][j] != MIN_WORLD_HEIGHT)
                {
                    tracemap.ground[i][j] = ground_min + (tracemap.ground[i][j] / scalefactor);
                }
            }
        }

        // SkyGround
        // calculate scalefactor
        if (skyground_max - skyground_min == 0)
        {
            scalefactor = 1.f;
        }
        else
        {
            // rain - scalefactor 254 to compensate for broken etmain behavior
            scalefactor = 254.f / (skyground_max - skyground_min);
        }

        // scale properly
        for (i = 0; i < TRACEMAP_SIZE; i++)
        {
            for (j = 0; j < TRACEMAP_SIZE; j++)
            {
                if (tracemap.skyground[i][j] != MAX_WORLD_HEIGHT)
                {
                    tracemap.skyground[i][j] = skyground_min + (tracemap.skyground[i][j] / scalefactor);
                }
            }
        }

        // Sky
        // calculate scalefactor
        if (sky_max - sky_min == 0)
        {
            scalefactor = 1.f;
        }
        else
        {
            // rain - scalefactor 254 to compensate for broken etmain behavior
            scalefactor = 254.f / (sky_max - sky_min);
        }

        // scale properly
        for (i = 0; i < TRACEMAP_SIZE; i++)
        {
            for (j = 0; j < TRACEMAP_SIZE; j++)
            {
                if (tracemap.sky[i][j] != MAX_WORLD_HEIGHT)
                {
                    tracemap.sky[i][j] = sky_min + (tracemap.sky[i][j] / scalefactor);
                }
            }
        }
    }
    else
    {
        return(tracemap.loaded = qfalse);
    }

    tracemap.world_mins[0] = world_mins[0];
    tracemap.world_mins[1] = world_mins[1];
    tracemap.world_maxs[0] = world_maxs[0];
    tracemap.world_maxs[1] = world_maxs[1];

    one_over_mapgrid_factor[0] = 1.f / ((tracemap.world_maxs[0] - tracemap.world_mins[0]) / (float)TRACEMAP_SIZE);
    one_over_mapgrid_factor[1] = 1.f / ((tracemap.world_maxs[1] - tracemap.world_mins[1]) / (float)TRACEMAP_SIZE);

    tracemap.groundfloor = ground_min;
    tracemap.groundceil  = ground_max;

    return(tracemap.loaded = qtrue);
}
Beispiel #12
0
/*
=================
R_LoadMD3
=================
*/
static qboolean R_LoadMD3 (model_t *mod, int lod, void *buffer, const char *mod_name, qboolean &bAlreadyCached ) {
	int					i, j;
	md3Header_t			*pinmodel;
	md3Surface_t		*surf;
	int					version;
	int					size;

#if 0 //#ifndef _M_IX86
	md3Frame_t			*frame;
	md3Triangle_t		*tri;
	md3St_t				*st;
	md3XyzNormal_t		*xyz;
	md3Tag_t			*tag;
#endif


	pinmodel= (md3Header_t *)buffer;
	//
	// read some fields from the binary, but only LittleLong() them when we know this wasn't an already-cached model...
	//
	version = pinmodel->version;
	size	= pinmodel->ofsEnd;

	if (!bAlreadyCached)
	{
		LL(version);
		LL(size);
	}

	if (version != MD3_VERSION) {
		Com_Printf (S_COLOR_YELLOW  "R_LoadMD3: %s has wrong version (%i should be %i)\n",
				 mod_name, version, MD3_VERSION);
		return qfalse;
	}

	mod->type      = MOD_MESH;
	mod->dataSize += size;

	qboolean bAlreadyFound = qfalse;
	mod->md3[lod] = (md3Header_t *) //Hunk_Alloc( size );
										RE_RegisterModels_Malloc(size, buffer, mod_name, &bAlreadyFound, TAG_MODEL_MD3);

	assert(bAlreadyCached == bAlreadyFound);	// I should probably eliminate 'bAlreadyFound', but wtf?

	if (!bAlreadyFound)
	{
		// horrible new hackery, if !bAlreadyFound then we've just done a tag-morph, so we need to set the
		//	bool reference passed into this function to true, to tell the caller NOT to do an ri->FS_Freefile since
		//	we've hijacked that memory block...
		//
		// Aaaargh. Kill me now...
		//
		bAlreadyCached = qtrue;
		assert( mod->md3[lod] == buffer );
//		memcpy( mod->md3[lod], buffer, size );	// and don't do this now, since it's the same thing

		LL(mod->md3[lod]->ident);
		LL(mod->md3[lod]->version);
		LL(mod->md3[lod]->numFrames);
		LL(mod->md3[lod]->numTags);
		LL(mod->md3[lod]->numSurfaces);
		LL(mod->md3[lod]->ofsFrames);
		LL(mod->md3[lod]->ofsTags);
		LL(mod->md3[lod]->ofsSurfaces);
		LL(mod->md3[lod]->ofsEnd);
	}

	if ( mod->md3[lod]->numFrames < 1 ) {
		Com_Printf (S_COLOR_YELLOW  "R_LoadMD3: %s has no frames\n", mod_name );
		return qfalse;
	}

	if (bAlreadyFound)
	{
		return qtrue;	// All done. Stop, go no further, do not pass Go...
	}

#if 0 //#ifndef _M_IX86
	//
	// optimisation, we don't bother doing this for standard intel case since our data's already in that format...
	//

	// swap all the frames
    frame = (md3Frame_t *) ( (byte *)mod->md3[lod] + mod->md3[lod]->ofsFrames );
    for ( i = 0 ; i < mod->md3[lod]->numFrames ; i++, frame++) {
    	frame->radius = LittleFloat( frame->radius );
        for ( j = 0 ; j < 3 ; j++ ) {
            frame->bounds[0][j] = LittleFloat( frame->bounds[0][j] );
            frame->bounds[1][j] = LittleFloat( frame->bounds[1][j] );
	    	frame->localOrigin[j] = LittleFloat( frame->localOrigin[j] );
        }
	}

	// swap all the tags
    tag = (md3Tag_t *) ( (byte *)mod->md3[lod] + mod->md3[lod]->ofsTags );
    for ( i = 0 ; i < mod->md3[lod]->numTags * mod->md3[lod]->numFrames ; i++, tag++) {
        for ( j = 0 ; j < 3 ; j++ ) {
			tag->origin[j] = LittleFloat( tag->origin[j] );
			tag->axis[0][j] = LittleFloat( tag->axis[0][j] );
			tag->axis[1][j] = LittleFloat( tag->axis[1][j] );
			tag->axis[2][j] = LittleFloat( tag->axis[2][j] );
        }
	}
#endif

	// swap all the surfaces
	surf = (md3Surface_t *) ( (byte *)mod->md3[lod] + mod->md3[lod]->ofsSurfaces );
	for ( i = 0 ; i < mod->md3[lod]->numSurfaces ; i++) {
        LL(surf->flags);
        LL(surf->numFrames);
        LL(surf->numShaders);
        LL(surf->numTriangles);
        LL(surf->ofsTriangles);
        LL(surf->numVerts);
        LL(surf->ofsShaders);
        LL(surf->ofsSt);
        LL(surf->ofsXyzNormals);
        LL(surf->ofsEnd);

		if ( surf->numVerts > SHADER_MAX_VERTEXES ) {
			Com_Error (ERR_DROP, "R_LoadMD3: %s has more than %i verts on a surface (%i)",
				mod_name, SHADER_MAX_VERTEXES, surf->numVerts );
		}
		if ( surf->numTriangles*3 > SHADER_MAX_INDEXES ) {
			Com_Error (ERR_DROP, "R_LoadMD3: %s has more than %i triangles on a surface (%i)",
				mod_name, SHADER_MAX_INDEXES / 3, surf->numTriangles );
		}

		// change to surface identifier
		surf->ident = SF_MD3;

		// lowercase the surface name so skin compares are faster
		Q_strlwr( surf->name );

		// strip off a trailing _1 or _2
		// this is a crutch for q3data being a mess
		j = strlen( surf->name );
		if ( j > 2 && surf->name[j-2] == '_' ) {
			surf->name[j-2] = 0;
		}
#if 0 //#ifndef _M_IX86
//
// optimisation, we don't bother doing this for standard intel case since our data's already in that format...
//

		// swap all the triangles
		tri = (md3Triangle_t *) ( (byte *)surf + surf->ofsTriangles );
		for ( j = 0 ; j < surf->numTriangles ; j++, tri++ ) {
			LL(tri->indexes[0]);
			LL(tri->indexes[1]);
			LL(tri->indexes[2]);
		}

		// swap all the ST
        st = (md3St_t *) ( (byte *)surf + surf->ofsSt );
        for ( j = 0 ; j < surf->numVerts ; j++, st++ ) {
            st->st[0] = LittleFloat( st->st[0] );
            st->st[1] = LittleFloat( st->st[1] );
        }

		// swap all the XyzNormals
        xyz = (md3XyzNormal_t *) ( (byte *)surf + surf->ofsXyzNormals );
        for ( j = 0 ; j < surf->numVerts * surf->numFrames ; j++, xyz++ )
		{
            xyz->xyz[0] = LittleShort( xyz->xyz[0] );
            xyz->xyz[1] = LittleShort( xyz->xyz[1] );
            xyz->xyz[2] = LittleShort( xyz->xyz[2] );

            xyz->normal = LittleShort( xyz->normal );
        }
#endif

		// find the next surface
		surf = (md3Surface_t *)( (byte *)surf + surf->ofsEnd );
	}

	return qtrue;
}
Beispiel #13
0
/*
===================
G_SpawnGEntityFromSpawnVars

Spawn an entity and fill in all of the level fields from
level.spawnVars[], then call the class specfic spawn function
===================
*/
void G_SpawnGEntityFromSpawnVars(void)
{
	int             i;
	gentity_t      *ent;
	char           *str;

	// get the next free entity
	ent = G_Spawn();

	for(i = 0; i < level.numSpawnVars; i++)
	{
		G_ParseField(level.spawnVars[i][0], level.spawnVars[i][1], ent);
	}

	// check for "notteam" / "notfree" flags
	G_SpawnInt("notteam", "0", &i);
	if(i)
	{
		G_FreeEntity(ent);
		return;
	}

	// allowteams handling
	G_SpawnString("allowteams", "", &str);
	if(str[0])
	{
		str = Q_strlwr(str);
		if(strstr(str, "axis"))
		{
			ent->allowteams |= ALLOW_AXIS_TEAM;
		}
		if(strstr(str, "allies"))
		{
			ent->allowteams |= ALLOW_ALLIED_TEAM;
		}
		if(strstr(str, "cvops"))
		{
			ent->allowteams |= ALLOW_DISGUISED_CVOPS;
		}
	}

	if(ent->targetname && *ent->targetname)
	{
		ent->targetnamehash = BG_StringHashValue(ent->targetname);
	}
	else
	{
		ent->targetnamehash = -1;
	}

	// move editor origin to pos
	VectorCopy(ent->s.origin, ent->s.pos.trBase);
	VectorCopy(ent->s.origin, ent->r.currentOrigin);

	// if we didn't get a classname, don't bother spawning anything
	if(!G_CallSpawn(ent))
	{
		G_FreeEntity(ent);
	}

	// RF, try and move it into the bot entities if possible
//  BotCheckBotGameEntity( ent );
}
Beispiel #14
0
/*
=================
R_LoadMDC
=================
*/
qboolean R_LoadMDC( model_t *mod, int lod, void *buffer, int bufferSize, const char *modName )
{
	int                i, j, k;

	mdcHeader_t        *mdcModel;
	md3Frame_t         *mdcFrame;
	mdcSurface_t       *mdcSurf;
	md3Shader_t        *mdcShader;
	md3Triangle_t      *mdcTri;
	md3St_t            *mdcst;
	md3XyzNormal_t     *mdcxyz;
	mdcXyzCompressed_t *mdcxyzComp;
	mdcTag_t           *mdcTag;
	mdcTagName_t       *mdcTagName;

	mdvModel_t         *mdvModel;
	mdvFrame_t         *frame;
	mdvSurface_t       *surf; //, *surface; //unused
	srfTriangle_t      *tri;
	mdvXyz_t           *v;
	mdvSt_t            *st;
	mdvTag_t           *tag;
	mdvTagName_t       *tagName;
	short              *ps;

	int                version;
	int                size;

	mdcModel = ( mdcHeader_t * ) buffer;

	version = LittleLong( mdcModel->version );

	if ( version != MDC_VERSION )
	{
		ri.Printf( PRINT_WARNING, "R_LoadMD3: %s has wrong version (%i should be %i)\n", modName, version, MDC_VERSION );
		return qfalse;
	}

	mod->type = MOD_MESH;
	size = LittleLong( mdcModel->ofsEnd );
	mod->dataSize += size;
	mdvModel = mod->mdv[ lod ] = (mdvModel_t*) ri.Hunk_Alloc( sizeof( mdvModel_t ), h_low );

	LL( mdcModel->ident );
	LL( mdcModel->version );
	LL( mdcModel->numFrames );
	LL( mdcModel->numTags );
	LL( mdcModel->numSurfaces );
	LL( mdcModel->ofsFrames );
	LL( mdcModel->ofsTags );
	LL( mdcModel->ofsSurfaces );
	LL( mdcModel->ofsEnd );
	LL( mdcModel->ofsEnd );
	LL( mdcModel->flags );
	LL( mdcModel->numSkins );

	if ( mdcModel->numFrames < 1 )
	{
		ri.Printf( PRINT_WARNING, "R_LoadMDC: '%s' has no frames\n", modName );
		return qfalse;
	}

	// swap all the frames
	mdvModel->numFrames = mdcModel->numFrames;
	mdvModel->frames = frame = (mdvFrame_t*) ri.Hunk_Alloc( sizeof( *frame ) * mdcModel->numFrames, h_low );

	mdcFrame = ( md3Frame_t * )( ( byte * ) mdcModel + mdcModel->ofsFrames );

	for ( i = 0; i < mdcModel->numFrames; i++, frame++, mdcFrame++ )
	{
#if 1

		// RB: ET HACK
		if ( strstr( mod->name, "sherman" ) || strstr( mod->name, "mg42" ) )
		{
			frame->radius = 256;

			for ( j = 0; j < 3; j++ )
			{
				frame->bounds[ 0 ][ j ] = 128;
				frame->bounds[ 1 ][ j ] = -128;
				frame->localOrigin[ j ] = LittleFloat( mdcFrame->localOrigin[ j ] );
			}
		}
		else
#endif
		{
			frame->radius = LittleFloat( mdcFrame->radius );

			for ( j = 0; j < 3; j++ )
			{
				frame->bounds[ 0 ][ j ] = LittleFloat( mdcFrame->bounds[ 0 ][ j ] );
				frame->bounds[ 1 ][ j ] = LittleFloat( mdcFrame->bounds[ 1 ][ j ] );
				frame->localOrigin[ j ] = LittleFloat( mdcFrame->localOrigin[ j ] );
			}
		}
	}

	// swap all the tags
	mdvModel->numTags = mdcModel->numTags;
	mdvModel->tags = tag = (mdvTag_t*) ri.Hunk_Alloc( sizeof( *tag ) * ( mdcModel->numTags * mdcModel->numFrames ), h_low );

	mdcTag = ( mdcTag_t * )( ( byte * ) mdcModel + mdcModel->ofsTags );

	for ( i = 0; i < mdcModel->numTags * mdcModel->numFrames; i++, tag++, mdcTag++ )
	{
		vec3_t angles;

		for ( j = 0; j < 3; j++ )
		{
			tag->origin[ j ] = ( float ) LittleShort( mdcTag->xyz[ j ] ) * MD3_XYZ_SCALE;
			angles[ j ] = ( float ) LittleShort( mdcTag->angles[ j ] ) * MDC_TAG_ANGLE_SCALE;
		}

		AnglesToAxis( angles, tag->axis );
	}

	mdvModel->tagNames = tagName = (mdvTagName_t*) ri.Hunk_Alloc( sizeof( *tagName ) * ( mdcModel->numTags ), h_low );

	mdcTagName = ( mdcTagName_t * )( ( byte * ) mdcModel + mdcModel->ofsTagNames );

	for ( i = 0; i < mdcModel->numTags; i++, tagName++, mdcTagName++ )
	{
		Q_strncpyz( tagName->name, mdcTagName->name, sizeof( tagName->name ) );
	}

	// swap all the surfaces
	mdvModel->numSurfaces = mdcModel->numSurfaces;
	mdvModel->surfaces = surf = (mdvSurface_t*) ri.Hunk_Alloc( sizeof( *surf ) * mdcModel->numSurfaces, h_low );

	mdcSurf = ( mdcSurface_t * )( ( byte * ) mdcModel + mdcModel->ofsSurfaces );

	for ( i = 0; i < mdcModel->numSurfaces; i++ )
	{
		LL( mdcSurf->ident );
		LL( mdcSurf->flags );
		LL( mdcSurf->numBaseFrames );
		LL( mdcSurf->numCompFrames );
		LL( mdcSurf->numShaders );
		LL( mdcSurf->numTriangles );
		LL( mdcSurf->ofsTriangles );
		LL( mdcSurf->numVerts );
		LL( mdcSurf->ofsShaders );
		LL( mdcSurf->ofsSt );
		LL( mdcSurf->ofsXyzNormals );
		LL( mdcSurf->ofsXyzNormals );
		LL( mdcSurf->ofsXyzCompressed );
		LL( mdcSurf->ofsFrameBaseFrames );
		LL( mdcSurf->ofsFrameCompFrames );
		LL( mdcSurf->ofsEnd );

		if ( mdcSurf->numVerts > SHADER_MAX_VERTEXES )
		{
			ri.Error( ERR_DROP, "R_LoadMDC: %s has more than %i verts on a surface (%i)",
			          modName, SHADER_MAX_VERTEXES, mdcSurf->numVerts );
		}

		if ( mdcSurf->numTriangles > SHADER_MAX_TRIANGLES )
		{
			ri.Error( ERR_DROP, "R_LoadMDC: %s has more than %i triangles on a surface (%i)",
			          modName, SHADER_MAX_TRIANGLES, mdcSurf->numTriangles );
		}

		// change to surface identifier
		surf->surfaceType = SF_MDV;

		// give pointer to model for Tess_SurfaceMDV
		surf->model = mdvModel;

		// copy surface name
		Q_strncpyz( surf->name, mdcSurf->name, sizeof( surf->name ) );

		// lowercase the surface name so skin compares are faster
		Q_strlwr( surf->name );

		// strip off a trailing _1 or _2
		// this is a crutch for q3data being a mess
		j = strlen( surf->name );

		if ( j > 2 && surf->name[ j - 2 ] == '_' )
		{
			surf->name[ j - 2 ] = 0;
		}

		// register the shaders

		/*
		   surf->numShaders = md3Surf->numShaders;
		   surf->shaders = shader = ri.Hunk_Alloc(sizeof(*shader) * md3Surf->numShaders, h_low);

		   md3Shader = (md3Shader_t *) ((byte *) md3Surf + md3Surf->ofsShaders);
		   for(j = 0; j < md3Surf->numShaders; j++, shader++, md3Shader++)
		   {
		   shader_t       *sh;

		   sh = R_FindShader(md3Shader->name, SHADER_3D_DYNAMIC, RSF_DEFAULT);
		   if(sh->defaultShader)
		   {
		   shader->shaderIndex = 0;
		   }
		   else
		   {
		   shader->shaderIndex = sh->index;
		   }
		   }
		 */

		// only consider the first shader
		mdcShader = ( md3Shader_t * )( ( byte * ) mdcSurf + mdcSurf->ofsShaders );
		surf->shader = R_FindShader( mdcShader->name, SHADER_3D_DYNAMIC, RSF_DEFAULT );

		// swap all the triangles
		surf->numTriangles = mdcSurf->numTriangles;
		surf->triangles = tri = (srfTriangle_t*) ri.Hunk_Alloc( sizeof( *tri ) * mdcSurf->numTriangles, h_low );

		mdcTri = ( md3Triangle_t * )( ( byte * ) mdcSurf + mdcSurf->ofsTriangles );

		for ( j = 0; j < mdcSurf->numTriangles; j++, tri++, mdcTri++ )
		{
			tri->indexes[ 0 ] = LittleLong( mdcTri->indexes[ 0 ] );
			tri->indexes[ 1 ] = LittleLong( mdcTri->indexes[ 1 ] );
			tri->indexes[ 2 ] = LittleLong( mdcTri->indexes[ 2 ] );
		}

		// swap all the XyzNormals
		mdcxyz = ( md3XyzNormal_t * )( ( byte * ) mdcSurf + mdcSurf->ofsXyzNormals );

		for ( j = 0; j < mdcSurf->numVerts * mdcSurf->numBaseFrames; j++, mdcxyz++ )
		{
			mdcxyz->xyz[ 0 ] = LittleShort( mdcxyz->xyz[ 0 ] );
			mdcxyz->xyz[ 1 ] = LittleShort( mdcxyz->xyz[ 1 ] );
			mdcxyz->xyz[ 2 ] = LittleShort( mdcxyz->xyz[ 2 ] );

			mdcxyz->normal = LittleShort( mdcxyz->normal );
		}

		// swap all the XyzCompressed
		mdcxyzComp = ( mdcXyzCompressed_t * )( ( byte * ) mdcSurf + mdcSurf->ofsXyzCompressed );

		for ( j = 0; j < mdcSurf->numVerts * mdcSurf->numCompFrames; j++, mdcxyzComp++ )
		{
			LL( mdcxyzComp->ofsVec );
		}

		// swap the frameBaseFrames
		ps = ( short * )( ( byte * ) mdcSurf + mdcSurf->ofsFrameBaseFrames );

		for ( j = 0; j < mdcModel->numFrames; j++, ps++ )
		{
			*ps = LittleShort( *ps );
		}

		// swap the frameCompFrames
		ps = ( short * )( ( byte * ) mdcSurf + mdcSurf->ofsFrameCompFrames );

		for ( j = 0; j < mdcModel->numFrames; j++, ps++ )
		{
			*ps = LittleShort( *ps );
		}

		surf->numVerts = mdcSurf->numVerts;
		surf->verts = v = (mdvXyz_t*) ri.Hunk_Alloc( sizeof( *v ) * ( mdcSurf->numVerts * mdcModel->numFrames ), h_low );

		for ( j = 0; j < mdcModel->numFrames; j++ )
		{
			int baseFrame;
			int compFrame = 0;

			baseFrame = ( int ) * ( ( short * )( ( byte * ) mdcSurf + mdcSurf->ofsFrameBaseFrames ) + j );

			mdcxyz = ( md3XyzNormal_t * )( ( byte * ) mdcSurf + mdcSurf->ofsXyzNormals + baseFrame * mdcSurf->numVerts * sizeof( md3XyzNormal_t ) );

			if ( mdcSurf->numCompFrames > 0 )
			{
				compFrame = ( int ) * ( ( short * )( ( byte * ) mdcSurf + mdcSurf->ofsFrameCompFrames ) + j );

				if ( compFrame >= 0 )
				{
					mdcxyzComp = ( mdcXyzCompressed_t * )( ( byte * ) mdcSurf + mdcSurf->ofsXyzCompressed + compFrame * mdcSurf->numVerts * sizeof( mdcXyzCompressed_t ) );
				}
			}

			for ( k = 0; k < mdcSurf->numVerts; k++, v++, mdcxyz++ )
			{
				v->xyz[ 0 ] = LittleShort( mdcxyz->xyz[ 0 ] ) * MD3_XYZ_SCALE;
				v->xyz[ 1 ] = LittleShort( mdcxyz->xyz[ 1 ] ) * MD3_XYZ_SCALE;
				v->xyz[ 2 ] = LittleShort( mdcxyz->xyz[ 2 ] ) * MD3_XYZ_SCALE;

				if ( mdcSurf->numCompFrames > 0 && compFrame >= 0 )
				{
					vec3_t ofsVec;
					//vec3_t    normal;

					R_MDC_DecodeXyzCompressed2( LittleShort( mdcxyzComp->ofsVec ), ofsVec /*, normal*/ );
					VectorAdd( v->xyz, ofsVec, v->xyz );

					mdcxyzComp++;
				}
			}
		}

		// swap all the ST
		surf->st = st = (mdvSt_t*) ri.Hunk_Alloc( sizeof( *st ) * mdcSurf->numVerts, h_low );

		mdcst = ( md3St_t * )( ( byte * ) mdcSurf + mdcSurf->ofsSt );

		for ( j = 0; j < mdcSurf->numVerts; j++, mdcst++, st++ )
		{
			st->st[ 0 ] = LittleFloat( mdcst->st[ 0 ] );
			st->st[ 1 ] = LittleFloat( mdcst->st[ 1 ] );
		}

		// find the next surface
		mdcSurf = ( mdcSurface_t * )( ( byte * ) mdcSurf + mdcSurf->ofsEnd );
		surf++;
	}

#if 1
	// create VBO surfaces from md3 surfaces
	{
		growList_t      vboSurfaces;
		srfVBOMDVMesh_t *vboSurf;
		vboData_t       data;

		int             f;

		Com_InitGrowList( &vboSurfaces, 10 );

		for ( i = 0, surf = mdvModel->surfaces; i < mdvModel->numSurfaces; i++, surf++ )
		{
			//allocate temp memory for vertex data
			memset( &data, 0, sizeof( data ) );
			data.xyz = ( vec3_t * ) ri.Hunk_AllocateTempMemory( sizeof( *data.xyz ) * mdvModel->numFrames * surf->numVerts );
			data.normal = ( vec3_t * ) ri.Hunk_AllocateTempMemory( sizeof( *data.normal ) * mdvModel->numFrames * surf->numVerts );
			data.tangent = ( vec3_t * ) ri.Hunk_AllocateTempMemory( sizeof( *data.tangent ) * mdvModel->numFrames * surf->numVerts );
			data.binormal = ( vec3_t * ) ri.Hunk_AllocateTempMemory( sizeof( *data.binormal ) * mdvModel->numFrames * surf->numVerts );
			data.numFrames = mdvModel->numFrames;
			data.st = ( vec2_t * ) ri.Hunk_AllocateTempMemory( sizeof( *data.st ) * surf->numVerts );
			data.numVerts = surf->numVerts;

			// feed vertex XYZ
			for ( f = 0; f < mdvModel->numFrames; f++ )
			{
				for ( j = 0; j < surf->numVerts; j++ )
				{
					VectorCopy( surf->verts[ f * surf->numVerts + j ].xyz, data.xyz[ f * surf->numVerts + j ] );
				}
			}

			// feed vertex texcoords
			for ( j = 0; j < surf->numVerts; j++ )
			{
				data.st[ j ][ 0 ] = surf->st[ j ].st[ 0 ];
				data.st[ j ][ 1 ] = surf->st[ j ].st[ 1 ];
			}

			// calc and feed tangent spaces
			{
				const float *v0, *v1, *v2;
				const float *t0, *t1, *t2;
				vec3_t      tangent;
				vec3_t      binormal;
				vec3_t      normal;

				for ( j = 0; j < ( surf->numVerts * mdvModel->numFrames ); j++ )
				{
					VectorClear( data.tangent[ j ] );
					VectorClear( data.binormal[ j ] );
					VectorClear( data.normal[ j ] );
				}

				for ( f = 0; f < mdvModel->numFrames; f++ )
				{
					for ( j = 0, tri = surf->triangles; j < surf->numTriangles; j++, tri++ )
					{
						v0 = surf->verts[ surf->numVerts * f + tri->indexes[ 0 ] ].xyz;
						v1 = surf->verts[ surf->numVerts * f + tri->indexes[ 1 ] ].xyz;
						v2 = surf->verts[ surf->numVerts * f + tri->indexes[ 2 ] ].xyz;

						t0 = surf->st[ tri->indexes[ 0 ] ].st;
						t1 = surf->st[ tri->indexes[ 1 ] ].st;
						t2 = surf->st[ tri->indexes[ 2 ] ].st;

#if 1
						R_CalcTangentSpace( tangent, binormal, normal, v0, v1, v2, t0, t1, t2 );
#else
						R_CalcNormalForTriangle( normal, v0, v1, v2 );
						R_CalcTangentsForTriangle( tangent, binormal, v0, v1, v2, t0, t1, t2 );
#endif

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

							v = data.tangent[ surf->numVerts * f + tri->indexes[ k ] ];
							VectorAdd( v, tangent, v );

							v = data.binormal[ surf->numVerts * f + tri->indexes[ k ] ];
							VectorAdd( v, binormal, v );

							v = data.normal[ surf->numVerts * f + tri->indexes[ k ] ];
							VectorAdd( v, normal, v );
						}
					}
				}

				for ( j = 0; j < ( surf->numVerts * mdvModel->numFrames ); j++ )
				{
					VectorNormalize( data.tangent[ j ] );
					VectorNormalize( data.binormal[ j ] );
					VectorNormalize( data.normal[ j ] );
				}
			}

			//ri.Printf(PRINT_ALL, "...calculating MD3 mesh VBOs ( '%s', %i verts %i tris )\n", surf->name, surf->numVerts, surf->numTriangles);

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

			vboSurf->surfaceType = SF_VBO_MDVMESH;
			vboSurf->mdvModel = mdvModel;
			vboSurf->mdvSurface = surf;
			vboSurf->numIndexes = surf->numTriangles * 3;
			vboSurf->numVerts = surf->numVerts;

			vboSurf->ibo = R_CreateStaticIBO2( va( "staticMD3Mesh_IBO %s", surf->name ), surf->numTriangles, surf->triangles );

			vboSurf->vbo = R_CreateStaticVBO( va( "staticMD3Mesh_VBO '%s'", surf->name ), data, VBO_LAYOUT_VERTEX_ANIMATION );
			
			ri.Hunk_FreeTempMemory( data.st );
			ri.Hunk_FreeTempMemory( data.binormal );
			ri.Hunk_FreeTempMemory( data.tangent );
			ri.Hunk_FreeTempMemory( data.normal );
			ri.Hunk_FreeTempMemory( data.xyz );
		}

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

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

		Com_DestroyGrowList( &vboSurfaces );
	}
#endif

	return qtrue;
}
Beispiel #15
0
/*
==================
GL_ResolveHardwareType

Chipset specific configuration
==================
*/
void GL_ResolveHardwareType( void )
{
	char		buf[ 1024 ];
	cvar_t	*lastValidRenderer = ri.Cvar_Get(
			"r_lastValidRenderer", "(uninitialized)", CVAR_ARCHIVE );

	Q_strncpyz( buf, glConfig.renderer_string, sizeof( buf ) );
	Q_strlwr( buf );

	// NOTE: if changing cvars, do it within this block.  This allows them
	// to be overridden when testing driver fixes, etc. but only sets
	// them to their default state when the hardware is first installed/run.
	if( Q_stricmp( lastValidRenderer->string, glConfig.renderer_string ) )
	{
		glConfig.hardwareType = GLHW_GENERIC;

		ri.Cvar_Set( "r_textureMode", GENERIC_HW_R_TEXTUREMODE_DEFAULT );

		// VOODOO GRAPHICS w/ 2MB
		if ( strstr( buf, "voodoo graphics/1 tmu/2 mb" ) )
		{
			ri.Cvar_Set( "r_picmip", "2" );
			ri.Cvar_Get( "r_picmip", "1", CVAR_ARCHIVE | CVAR_LATCH );
		}
		else
		{
			ri.Cvar_Set( "r_picmip", GENERIC_HW_R_PICMIP_DEFAULT );

			if ( strstr( buf, "rage 128" ) || strstr( buf, "rage128" ) )
			{
				ri.Cvar_Set( "r_finish", "0" );
			}
			// Savage3D and Savage4 should always have trilinear enabled
			else if ( strstr( buf, "savage3d" ) || strstr( buf, "s3 savage4" ) )
			{
				ri.Cvar_Set( "r_texturemode", "GL_LINEAR_MIPMAP_LINEAR" );
			}
		}
	}
	
	//
	// this is where hardware specific workarounds that should be
	// detected/initialized every startup should go.
	//
	if ( strstr( buf, "banshee" ) || strstr( buf, "voodoo3" ) )
	{
		glConfig.hardwareType = GLHW_3DFX_2D3D;
	}
	// VOODOO GRAPHICS w/ 2MB
	else if ( strstr( buf, "voodoo graphics/1 tmu/2 mb" ) )
	{
	}
	else if ( strstr( buf, "glzicd" ) )
	{
	}
	else if ( strstr( buf, "rage pro" ) ||
			strstr( buf, "Rage Pro" ) ||
			strstr( buf, "ragepro" ) )
	{
		glConfig.hardwareType = GLHW_RAGEPRO;
	}
	else if ( strstr( buf, "rage 128" ) )
	{
	}
	else if ( strstr( buf, "permedia2" ) )
	{
		glConfig.hardwareType = GLHW_PERMEDIA2;
	}
	else if ( strstr( buf, "riva 128" ) )
	{
		glConfig.hardwareType = GLHW_RIVA128;
	}
	else if ( strstr( buf, "riva tnt " ) )
	{
	}
}
Beispiel #16
0
/*
===============
RE_RegisterSkin

===============
*/
qhandle_t RE_RegisterSkin(const char *name)
{
	qhandle_t       hSkin;
	skin_t         *skin;
	skinSurface_t  *surf;
	skinModel_t    *model;		//----(SA) added
	char           *text, *text_p;
	char           *token;
	char            surfName[MAX_QPATH];

	if(!name || !name[0])
	{
		Com_Printf("Empty name passed to RE_RegisterSkin\n");
		return 0;
	}

	if(strlen(name) >= MAX_QPATH)
	{
		Com_Printf("Skin name exceeds MAX_QPATH\n");
		return 0;
	}


	// see if the skin is already loaded
	for(hSkin = 1; hSkin < tr.numSkins; hSkin++)
	{
		skin = tr.skins[hSkin];
		if(!Q_stricmp(skin->name, name))
		{
			if(skin->numSurfaces == 0)
			{
				return 0;		// default skin
			}
			return hSkin;
		}
	}

	// allocate a new skin
	if(tr.numSkins == MAX_SKINS)
	{
		ri.Printf(PRINT_WARNING, "WARNING: RE_RegisterSkin( '%s' ) MAX_SKINS hit\n", name);
		return 0;
	}

//----(SA)  moved things around slightly to fix the problem where you restart
//          a map that has ai characters who had invalid skin names entered
//          in thier "skin" or "head" field

	// make sure the render thread is stopped
	R_SyncRenderThread();

#if 0
	// If not a .skin file, load as a single shader
	if(strcmp(name + strlen(name) - 5, ".skin"))
	{
		skin->numSurfaces = 1;
		skin->surfaces[0] = ri.Hunk_Alloc(sizeof(skin->surfaces[0]), h_low);
		skin->surfaces[0]->shader = R_FindShader(name, SHADER_3D_DYNAMIC, true);
		return hSkin;
	}
#endif

	// load and parse the skin file
	ri.FS_ReadFile(name, (void **)&text);
	if(!text)
	{
		return 0;
	}

	tr.numSkins++;
	skin = (skin_t*)ri.Hunk_Alloc(sizeof(skin_t), h_low);
	tr.skins[hSkin] = skin;
	Q_strncpyz(skin->name, name, sizeof(skin->name));
	skin->numSurfaces = 0;
	skin->numModels = 0;		//----(SA) added

//----(SA)  end

	text_p = text;
	while(text_p && *text_p)
	{
		// get surface name
		token = CommaParse(&text_p);
		Q_strncpyz(surfName, token, sizeof(surfName));

		if(!token[0])
		{
			break;
		}
		// lowercase the surface name so skin compares are faster
		Q_strlwr(surfName);

		if(*text_p == ',')
		{
			text_p++;
		}

		if(!Q_stricmpn(token, "tag_", 4))
		{
			continue;
		}

		if(!Q_stricmpn(token, "md3_", 4))
		{
			// this is specifying a model
			model = skin->models[skin->numModels] = (skinModel_t*)ri.Hunk_Alloc(sizeof(*skin->models[0]), h_low);
			Q_strncpyz(model->type, token, sizeof(model->type));
			model->hash = Com_HashKey(model->type, sizeof(model->type));

			// get the model name
			token = CommaParse(&text_p);

			Q_strncpyz(model->model, token, sizeof(model->model));

			skin->numModels++;
			continue;
		}

		// parse the shader name
		token = CommaParse(&text_p);

		surf = skin->surfaces[skin->numSurfaces] = (skinSurface_t*)ri.Hunk_Alloc(sizeof(*skin->surfaces[0]), h_low);
		Q_strncpyz(surf->name, surfName, sizeof(surf->name));

		// RB: bspSurface not not have ::hash yet
//		surf->hash = Com_HashKey(surf->name, sizeof(surf->name));
		surf->shader = R_FindShader(token, SHADER_3D_DYNAMIC, true);
		skin->numSurfaces++;
	}

	ri.FS_FreeFile(text);

	// never let a skin have 0 shaders
	if(skin->numSurfaces == 0)
	{
		return 0;				// use default skin
	}

	return hSkin;
}
Beispiel #17
0
// given a name, go get the skin we want and return
qhandle_t RE_RegisterIndividualSkin( const char *name , qhandle_t hSkin)
{
    skin_t			*skin;
    skinSurface_t	*surf;
    char			*text, *text_p;
    char			*token;
    char			surfName[MAX_QPATH];

    // load and parse the skin file
    ri->FS_ReadFile( name, (void **)&text );
    if ( !text ) {
#ifndef FINAL_BUILD
        Com_Printf( "WARNING: RE_RegisterSkin( '%s' ) failed to load!\n", name );
#endif
        return 0;
    }

    assert (tr.skins[hSkin]);	//should already be setup, but might be an 3part append

    skin = tr.skins[hSkin];

    text_p = text;
    while ( text_p && *text_p ) {
        // get surface name
        token = CommaParse( &text_p );
        Q_strncpyz( surfName, token, sizeof( surfName ) );

        if ( !token[0] ) {
            break;
        }
        // lowercase the surface name so skin compares are faster
        Q_strlwr( surfName );

        if ( *text_p == ',' ) {
            text_p++;
        }

        if ( !strncmp( token, "tag_", 4 ) ) {	//these aren't in there, but just in case you load an id style one...
            continue;
        }

        // parse the shader name
        token = CommaParse( &text_p );

        if ( !strcmp( &surfName[strlen(surfName)-4], "_off") )
        {
            if ( !strcmp( token ,"*off" ) )
            {
                continue;	//don't need these double offs
            }
            surfName[strlen(surfName)-4] = 0;	//remove the "_off"
        }
        if ( (unsigned)skin->numSurfaces >= ARRAY_LEN( skin->surfaces ) )
        {
            assert( ARRAY_LEN( skin->surfaces ) > (unsigned)skin->numSurfaces );
            Com_Printf( "WARNING: RE_RegisterSkin( '%s' ) more than %d surfaces!\n", name, ARRAY_LEN( skin->surfaces ) );
            break;
        }
        surf = (skinSurface_t *) Hunk_Alloc( sizeof( *skin->surfaces[0] ), h_low );
        skin->surfaces[skin->numSurfaces] = (_skinSurface_t *)surf;

        Q_strncpyz( surf->name, surfName, sizeof( surf->name ) );

        if (gServerSkinHack)	surf->shader = R_FindServerShader( token, lightmapsNone, stylesDefault, qtrue );
        else					surf->shader = R_FindShader( token, lightmapsNone, stylesDefault, qtrue );
        skin->numSurfaces++;
    }

    ri->FS_FreeFile( text );


    // never let a skin have 0 shaders
    if ( skin->numSurfaces == 0 ) {
        return 0;		// use default skin
    }

    return hSkin;
}
Beispiel #18
0
static qboolean BG_RAG_ParseAnimFile(int handle, animModelInfo_t *animModelInfo)
{
	pc_token_t token;
#ifdef CGAMEDLL
	qhandle_t mdxFile;
#else
	char mdxFileName[MAX_QPATH];
#endif // CGAMEDLL

	animation_t *animation;

	if (!trap_PC_ReadToken(handle, &token))
	{
		return BG_RAG_ParseError(handle, "expected mdx filename");
	}

#ifdef CGAMEDLL
	if (!(mdxFile = trap_R_RegisterModel(token.string)))
	{
		return BG_RAG_ParseError(handle, "failed to load %s", token.string);
	}
#else
	Q_strncpyz(mdxFileName, token.string, sizeof(mdxFileName));
#endif // CGAMEDLL

	if (!trap_PC_ReadToken(handle, &token) || Q_stricmp(token.string, "{"))
	{
		return BG_RAG_ParseError(handle, "expected '{'");
	}

	while (1)
	{
		if (!trap_PC_ReadToken(handle, &token))
		{
			return BG_RAG_ParseError(handle, "unexpected EOF");
		}

		if (token.string[0] == '}')
		{
			break;
		}

#ifdef CGAMEDLL
		if (!(animation = BG_RAG_FindFreeAnimation(mdxFile, token.string)))
		{
#else
		if (!(animation = BG_RAG_FindFreeAnimation(mdxFileName, token.string)))
		{
#endif // CGAMEDLL
			return BG_RAG_ParseError(handle, "out of animation storage space");
		}

		Q_strncpyz(animation->name, token.string, sizeof(animation->name));
		Q_strlwr(animation->name);

		if (!BG_RAG_ParseAnimation(handle, animation))
		{
			return qfalse;
		}

		animModelInfo->animations[animModelInfo->numAnimations] = animation;
		animModelInfo->numAnimations++;
	}

	return qtrue;
}

qboolean BG_R_RegisterAnimationGroup(const char *filename, animModelInfo_t *animModelInfo)
{
	pc_token_t token;
	int        handle;

	animModelInfo->numAnimations = 0;
	animModelInfo->footsteps     = FOOTSTEP_NORMAL;
	animModelInfo->gender        = GENDER_MALE;
	animModelInfo->isSkeletal    = qtrue;
	animModelInfo->version       = 3;
	animModelInfo->numHeadAnims  = 0;

	handle = trap_PC_LoadSource(filename);

	if (!handle)
	{
		return qfalse;
	}

	if (!trap_PC_ReadToken(handle, &token) || Q_stricmp(token.string, "animgroup"))
	{
		return BG_RAG_ParseError(handle, "expected 'animgroup'");
	}

	if (!trap_PC_ReadToken(handle, &token) || Q_stricmp(token.string, "{"))
	{
		return BG_RAG_ParseError(handle, "expected '{'");
	}

	while (1)
	{
		if (!trap_PC_ReadToken(handle, &token))
		{
			break;
		}

		if (token.string[0] == '}')
		{
			break;
		}

		if (!Q_stricmp(token.string, "animfile"))
		{
			if (!BG_RAG_ParseAnimFile(handle, animModelInfo))
			{
				return qfalse;
			}
		}
		else
		{
			return BG_RAG_ParseError(handle, "unknown token '%s'", token.string);
		}
	}

	trap_PC_FreeSource(handle);

	return qtrue;
}
Beispiel #19
0
/*
=================
R_LoadIQM

Load an IQM model and compute the joint matrices for every frame.
=================
*/
qboolean R_LoadIQM(model_t* mod, void* buffer, int filesize, const char* mod_name) {
    iqmHeader_t*     header;
    iqmVertexArray_t*    vertexarray;
    iqmTriangle_t*       triangle;
    iqmMesh_t*       mesh;
    iqmJoint_t*      joint;
    iqmPose_t*       pose;
    iqmBounds_t*     bounds;
    unsigned short*      framedata;
    char*            str;
    int         i, j;
    float           jointMats[IQM_MAX_JOINTS * 2 * 12];
    float*           mat;
    size_t          size, joint_names;
    iqmData_t*       iqmData;
    srfIQModel_t*        surface;

    if (filesize < sizeof(iqmHeader_t)) {
        return qfalse;
    }

    header = (iqmHeader_t*)buffer;
    if (Q_strncmp(header->magic, IQM_MAGIC, sizeof(header->magic))) {
        return qfalse;
    }

    LL(header->version);
    if (header->version != IQM_VERSION) {
        ri.Printf(PRINT_WARNING, "R_LoadIQM: %s is a unsupported IQM version (%d), only version %d is supported.\n",
                  mod_name, header->version, IQM_VERSION);
        return qfalse;
    }

    LL(header->filesize);
    if (header->filesize > filesize || header->filesize > 16 << 20) {
        return qfalse;
    }

    LL(header->flags);
    LL(header->num_text);
    LL(header->ofs_text);
    LL(header->num_meshes);
    LL(header->ofs_meshes);
    LL(header->num_vertexarrays);
    LL(header->num_vertexes);
    LL(header->ofs_vertexarrays);
    LL(header->num_triangles);
    LL(header->ofs_triangles);
    LL(header->ofs_adjacency);
    LL(header->num_joints);
    LL(header->ofs_joints);
    LL(header->num_poses);
    LL(header->ofs_poses);
    LL(header->num_anims);
    LL(header->ofs_anims);
    LL(header->num_frames);
    LL(header->num_framechannels);
    LL(header->ofs_frames);
    LL(header->ofs_bounds);
    LL(header->num_comment);
    LL(header->ofs_comment);
    LL(header->num_extensions);
    LL(header->ofs_extensions);

    // check ioq3 joint limit
    if (header->num_joints > IQM_MAX_JOINTS) {
        ri.Printf(PRINT_WARNING, "R_LoadIQM: %s has more than %d joints (%d).\n",
                  mod_name, IQM_MAX_JOINTS, header->num_joints);
        return qfalse;
    }

    // check and swap vertex arrays
    if (IQM_CheckRange(header, header->ofs_vertexarrays,
                       header->num_vertexarrays,
                       sizeof(iqmVertexArray_t))) {
        return qfalse;
    }
    vertexarray = (iqmVertexArray_t*)((byte*)header + header->ofs_vertexarrays);
    for (i = 0; i < header->num_vertexarrays; i++, vertexarray++) {
        int j, n, *intPtr;

        if (vertexarray->size <= 0 || vertexarray->size > 4) {
            return qfalse;
        }

        // total number of values
        n = header->num_vertexes * vertexarray->size;

        switch (vertexarray->format) {
            case IQM_BYTE:
            case IQM_UBYTE:
                // 1 byte, no swapping necessary
                if (IQM_CheckRange(header, vertexarray->offset,
                                   n, sizeof(byte))) {
                    return qfalse;
                }
                break;
            case IQM_INT:
            case IQM_UINT:
            case IQM_FLOAT:
                // 4-byte swap
                if (IQM_CheckRange(header, vertexarray->offset,
                                   n, sizeof(float))) {
                    return qfalse;
                }
                intPtr = (int*)((byte*)header + vertexarray->offset);
                for (j = 0; j < n; j++, intPtr++) {
                    LL(*intPtr);
                }
                break;
            default:
                // not supported
                return qfalse;
                break;
        }

        switch (vertexarray->type) {
            case IQM_POSITION:
            case IQM_NORMAL:
                if (vertexarray->format != IQM_FLOAT ||
                        vertexarray->size != 3) {
                    return qfalse;
                }
                break;
            case IQM_TANGENT:
                if (vertexarray->format != IQM_FLOAT ||
                        vertexarray->size != 4) {
                    return qfalse;
                }
                break;
            case IQM_TEXCOORD:
                if (vertexarray->format != IQM_FLOAT ||
                        vertexarray->size != 2) {
                    return qfalse;
                }
                break;
            case IQM_BLENDINDEXES:
            case IQM_BLENDWEIGHTS:
                if (vertexarray->format != IQM_UBYTE ||
                        vertexarray->size != 4) {
                    return qfalse;
                }
                break;
            case IQM_COLOR:
                if (vertexarray->format != IQM_UBYTE ||
                        vertexarray->size != 4) {
                    return qfalse;
                }
                break;
        }
    }

    // check and swap triangles
    if (IQM_CheckRange(header, header->ofs_triangles,
                       header->num_triangles, sizeof(iqmTriangle_t))) {
        return qfalse;
    }
    triangle = (iqmTriangle_t*)((byte*)header + header->ofs_triangles);
    for (i = 0; i < header->num_triangles; i++, triangle++) {
        LL(triangle->vertex[0]);
        LL(triangle->vertex[1]);
        LL(triangle->vertex[2]);

        if (triangle->vertex[0] > header->num_vertexes ||
                triangle->vertex[1] > header->num_vertexes ||
                triangle->vertex[2] > header->num_vertexes) {
            return qfalse;
        }
    }

    // check and swap meshes
    if (IQM_CheckRange(header, header->ofs_meshes,
                       header->num_meshes, sizeof(iqmMesh_t))) {
        return qfalse;
    }
    mesh = (iqmMesh_t*)((byte*)header + header->ofs_meshes);
    for (i = 0; i < header->num_meshes; i++, mesh++) {
        LL(mesh->name);
        LL(mesh->material);
        LL(mesh->first_vertex);
        LL(mesh->num_vertexes);
        LL(mesh->first_triangle);
        LL(mesh->num_triangles);

        // check ioq3 limits
        if (mesh->num_vertexes > SHADER_MAX_VERTEXES) {
            ri.Printf(PRINT_WARNING, "R_LoadIQM: %s has more than %i verts on a surface (%i).\n",
                      mod_name, SHADER_MAX_VERTEXES, mesh->num_vertexes);
            return qfalse;
        }
        if (mesh->num_triangles * 3 > SHADER_MAX_INDEXES) {
            ri.Printf(PRINT_WARNING, "R_LoadIQM: %s has more than %i triangles on a surface (%i).\n",
                      mod_name, SHADER_MAX_INDEXES / 3, mesh->num_triangles);
            return qfalse;
        }

        if (mesh->first_vertex >= header->num_vertexes ||
                mesh->first_vertex + mesh->num_vertexes > header->num_vertexes ||
                mesh->first_triangle >= header->num_triangles ||
                mesh->first_triangle + mesh->num_triangles > header->num_triangles ||
                mesh->name >= header->num_text ||
                mesh->material >= header->num_text) {
            return qfalse;
        }
    }

    // check and swap joints
    if (IQM_CheckRange(header, header->ofs_joints,
                       header->num_joints, sizeof(iqmJoint_t))) {
        return qfalse;
    }
    joint = (iqmJoint_t*)((byte*)header + header->ofs_joints);
    joint_names = 0;
    for (i = 0; i < header->num_joints; i++, joint++) {
        LL(joint->name);
        LL(joint->parent);
        LL(joint->translate[0]);
        LL(joint->translate[1]);
        LL(joint->translate[2]);
        LL(joint->rotate[0]);
        LL(joint->rotate[1]);
        LL(joint->rotate[2]);
        LL(joint->rotate[3]);
        LL(joint->scale[0]);
        LL(joint->scale[1]);
        LL(joint->scale[2]);

        if (joint->parent < -1 ||
                joint->parent >= (int)header->num_joints ||
                joint->name >= (int)header->num_text) {
            return qfalse;
        }
        joint_names += strlen((char*)header + header->ofs_text +
                              joint->name) + 1;
    }

    // check and swap poses
    if (header->num_poses != header->num_joints) {
        return qfalse;
    }
    if (IQM_CheckRange(header, header->ofs_poses,
                       header->num_poses, sizeof(iqmPose_t))) {
        return qfalse;
    }
    pose = (iqmPose_t*)((byte*)header + header->ofs_poses);
    for (i = 0; i < header->num_poses; i++, pose++) {
        LL(pose->parent);
        LL(pose->mask);
        LL(pose->channeloffset[0]);
        LL(pose->channeloffset[1]);
        LL(pose->channeloffset[2]);
        LL(pose->channeloffset[3]);
        LL(pose->channeloffset[4]);
        LL(pose->channeloffset[5]);
        LL(pose->channeloffset[6]);
        LL(pose->channeloffset[7]);
        LL(pose->channeloffset[8]);
        LL(pose->channeloffset[9]);
        LL(pose->channelscale[0]);
        LL(pose->channelscale[1]);
        LL(pose->channelscale[2]);
        LL(pose->channelscale[3]);
        LL(pose->channelscale[4]);
        LL(pose->channelscale[5]);
        LL(pose->channelscale[6]);
        LL(pose->channelscale[7]);
        LL(pose->channelscale[8]);
        LL(pose->channelscale[9]);
    }

    if (header->ofs_bounds) {
        // check and swap model bounds
        if (IQM_CheckRange(header, header->ofs_bounds,
                           header->num_frames, sizeof(*bounds))) {
            return qfalse;
        }
        bounds = (iqmBounds_t*)((byte*) header + header->ofs_bounds);
        for (i = 0; i < header->num_frames; i++) {
            LL(bounds->bbmin[0]);
            LL(bounds->bbmin[1]);
            LL(bounds->bbmin[2]);
            LL(bounds->bbmax[0]);
            LL(bounds->bbmax[1]);
            LL(bounds->bbmax[2]);

            bounds++;
        }
    }

    // allocate the model and copy the data
    size = sizeof(iqmData_t);
    size += header->num_meshes * sizeof(srfIQModel_t);
    size += header->num_joints * header->num_frames * 12 * sizeof(float);
    if (header->ofs_bounds)
        size += header->num_frames * 6 * sizeof(float); // model bounds
    size += header->num_vertexes * 3 * sizeof(float);   // positions
    size += header->num_vertexes * 2 * sizeof(float);   // texcoords
    size += header->num_vertexes * 3 * sizeof(float);   // normals
    size += header->num_vertexes * 4 * sizeof(float);   // tangents
    size += header->num_vertexes * 4 * sizeof(byte);    // blendIndexes
    size += header->num_vertexes * 4 * sizeof(byte);    // blendWeights
    size += header->num_vertexes * 4 * sizeof(byte);    // colors
    size += header->num_joints * sizeof(int);       // parents
    size += header->num_triangles * 3 * sizeof(int);    // triangles
    size += joint_names;                    // joint names

    mod->type = MOD_IQM;
    iqmData = (iqmData_t*)ri.Hunk_Alloc(size, h_low);
    mod->modelData = iqmData;

    // fill header
    iqmData->num_vertexes = header->num_vertexes;
    iqmData->num_triangles = header->num_triangles;
    iqmData->num_frames   = header->num_frames;
    iqmData->num_surfaces = header->num_meshes;
    iqmData->num_joints   = header->num_joints;
    iqmData->surfaces     = (srfIQModel_t*)(iqmData + 1);
    iqmData->poseMats     = (float*)(iqmData->surfaces + iqmData->num_surfaces);
    if (header->ofs_bounds) {
        iqmData->bounds       = iqmData->poseMats + 12 * header->num_joints * header->num_frames;
        iqmData->positions    = iqmData->bounds + 6 * header->num_frames;
    } else
        iqmData->positions    = iqmData->poseMats + 12 * header->num_joints * header->num_frames;
    iqmData->texcoords    = iqmData->positions + 3 * header->num_vertexes;
    iqmData->normals      = iqmData->texcoords + 2 * header->num_vertexes;
    iqmData->tangents     = iqmData->normals + 3 * header->num_vertexes;
    iqmData->blendIndexes = (byte*)(iqmData->tangents + 4 * header->num_vertexes);
    iqmData->blendWeights = iqmData->blendIndexes + 4 * header->num_vertexes;
    iqmData->colors       = iqmData->blendWeights + 4 * header->num_vertexes;
    iqmData->jointParents = (int*)(iqmData->colors + 4 * header->num_vertexes);
    iqmData->triangles    = iqmData->jointParents + header->num_joints;
    iqmData->names        = (char*)(iqmData->triangles + 3 * header->num_triangles);

    // calculate joint matrices and their inverses
    // they are needed only until the pose matrices are calculated
    mat = jointMats;
    joint = (iqmJoint_t*)((byte*)header + header->ofs_joints);
    for (i = 0; i < header->num_joints; i++, joint++) {
        float baseFrame[12], invBaseFrame[12];

        JointToMatrix(joint->rotate, joint->scale, joint->translate, baseFrame);
        Matrix34Invert(baseFrame, invBaseFrame);

        if (joint->parent >= 0) {
            Matrix34Multiply(jointMats + 2 * 12 * joint->parent, baseFrame, mat);
            mat += 12;
            Matrix34Multiply(invBaseFrame, jointMats + 2 * 12 * joint->parent + 12, mat);
            mat += 12;
        } else {
            Com_Memcpy(mat, baseFrame,    sizeof(baseFrame));
            mat += 12;
            Com_Memcpy(mat, invBaseFrame, sizeof(invBaseFrame));
            mat += 12;
        }
    }

    // calculate pose matrices
    framedata = (unsigned short*)((byte*)header + header->ofs_frames);
    mat = iqmData->poseMats;
    for (i = 0; i < header->num_frames; i++) {
        pose = (iqmPose_t*)((byte*)header + header->ofs_poses);
        for (j = 0; j < header->num_poses; j++, pose++) {
            vec3_t  translate;
            vec4_t  rotate;
            vec3_t  scale;
            float   mat1[12], mat2[12];

            translate[0] = pose->channeloffset[0];
            if (pose->mask & 0x001)
                translate[0] += *framedata++ * pose->channelscale[0];
            translate[1] = pose->channeloffset[1];
            if (pose->mask & 0x002)
                translate[1] += *framedata++ * pose->channelscale[1];
            translate[2] = pose->channeloffset[2];
            if (pose->mask & 0x004)
                translate[2] += *framedata++ * pose->channelscale[2];

            rotate[0] = pose->channeloffset[3];
            if (pose->mask & 0x008)
                rotate[0] += *framedata++ * pose->channelscale[3];
            rotate[1] = pose->channeloffset[4];
            if (pose->mask & 0x010)
                rotate[1] += *framedata++ * pose->channelscale[4];
            rotate[2] = pose->channeloffset[5];
            if (pose->mask & 0x020)
                rotate[2] += *framedata++ * pose->channelscale[5];
            rotate[3] = pose->channeloffset[6];
            if (pose->mask & 0x040)
                rotate[3] += *framedata++ * pose->channelscale[6];

            scale[0] = pose->channeloffset[7];
            if (pose->mask & 0x080)
                scale[0] += *framedata++ * pose->channelscale[7];
            scale[1] = pose->channeloffset[8];
            if (pose->mask & 0x100)
                scale[1] += *framedata++ * pose->channelscale[8];
            scale[2] = pose->channeloffset[9];
            if (pose->mask & 0x200)
                scale[2] += *framedata++ * pose->channelscale[9];

            // construct transformation matrix
            JointToMatrix(rotate, scale, translate, mat1);

            if (pose->parent >= 0) {
                Matrix34Multiply(jointMats + 12 * 2 * pose->parent,
                                 mat1, mat2);
            } else {
                Com_Memcpy(mat2, mat1, sizeof(mat1));
            }

            Matrix34Multiply(mat2, jointMats + 12 * (2 * j + 1), mat);
            mat += 12;
        }
    }

    // register shaders
    // overwrite the material offset with the shader index
    mesh = (iqmMesh_t*)((byte*)header + header->ofs_meshes);
    surface = iqmData->surfaces;
    str = (char*)header + header->ofs_text;
    for (i = 0; i < header->num_meshes; i++, mesh++, surface++) {
        surface->surfaceType = SF_IQM;
        Q_strncpyz(surface->name, str + mesh->name, sizeof(surface->name));
        Q_strlwr(surface->name); // lowercase the surface name so skin compares are faster
        surface->shader = R_FindShader(str + mesh->material, LIGHTMAP_NONE, qtrue);
        if (surface->shader->defaultShader)
            surface->shader = tr.defaultShader;
        surface->data = iqmData;
        surface->first_vertex = mesh->first_vertex;
        surface->num_vertexes = mesh->num_vertexes;
        surface->first_triangle = mesh->first_triangle;
        surface->num_triangles = mesh->num_triangles;
    }

    // copy vertexarrays and indexes
    vertexarray = (iqmVertexArray_t*)((byte*)header + header->ofs_vertexarrays);
    for (i = 0; i < header->num_vertexarrays; i++, vertexarray++) {
        int n;

        // total number of values
        n = header->num_vertexes * vertexarray->size;

        switch (vertexarray->type) {
            case IQM_POSITION:
                Com_Memcpy(iqmData->positions,
                           (byte*)header + vertexarray->offset,
                           n * sizeof(float));
                break;
            case IQM_NORMAL:
                Com_Memcpy(iqmData->normals,
                           (byte*)header + vertexarray->offset,
                           n * sizeof(float));
                break;
            case IQM_TANGENT:
                Com_Memcpy(iqmData->tangents,
                           (byte*)header + vertexarray->offset,
                           n * sizeof(float));
                break;
            case IQM_TEXCOORD:
                Com_Memcpy(iqmData->texcoords,
                           (byte*)header + vertexarray->offset,
                           n * sizeof(float));
                break;
            case IQM_BLENDINDEXES:
                Com_Memcpy(iqmData->blendIndexes,
                           (byte*)header + vertexarray->offset,
                           n * sizeof(byte));
                break;
            case IQM_BLENDWEIGHTS:
                Com_Memcpy(iqmData->blendWeights,
                           (byte*)header + vertexarray->offset,
                           n * sizeof(byte));
                break;
            case IQM_COLOR:
                Com_Memcpy(iqmData->colors,
                           (byte*)header + vertexarray->offset,
                           n * sizeof(byte));
                break;
        }
    }

    // copy joint parents
    joint = (iqmJoint_t*)((byte*)header + header->ofs_joints);
    for (i = 0; i < header->num_joints; i++, joint++) {
        iqmData->jointParents[i] = joint->parent;
    }

    // copy triangles
    triangle = (iqmTriangle_t*)((byte*)header + header->ofs_triangles);
    for (i = 0; i < header->num_triangles; i++, triangle++) {
        iqmData->triangles[3 * i + 0] = triangle->vertex[0];
        iqmData->triangles[3 * i + 1] = triangle->vertex[1];
        iqmData->triangles[3 * i + 2] = triangle->vertex[2];
    }

    // copy joint names
    str = iqmData->names;
    joint = (iqmJoint_t*)((byte*)header + header->ofs_joints);
    for (i = 0; i < header->num_joints; i++, joint++) {
        char* name = (char*)header + header->ofs_text +
                     joint->name;
        int len = strlen(name) + 1;
        Com_Memcpy(str, name, len);
        str += len;
    }

    // copy model bounds
    if (header->ofs_bounds) {
        mat = iqmData->bounds;
        bounds = (iqmBounds_t*)((byte*) header + header->ofs_bounds);
        for (i = 0; i < header->num_frames; i++) {
            mat[0] = bounds->bbmin[0];
            mat[1] = bounds->bbmin[1];
            mat[2] = bounds->bbmin[2];
            mat[3] = bounds->bbmax[0];
            mat[4] = bounds->bbmax[1];
            mat[5] = bounds->bbmax[2];

            mat += 6;
            bounds++;
        }
    }

    return qtrue;
}
Beispiel #20
0
/*
** GLimp_Init
**
** This is the platform specific OpenGL initialization function.  It
** is responsible for loading OpenGL, initializing it, setting
** extensions, creating a window of the appropriate size, doing
** fullscreen manipulations, etc.  Its overall responsibility is
** to make sure that a functional OpenGL subsystem is operating
** when it returns to the ref.
*/
void GLimp_Init( void )
{
	char	buf[1024];
	cvar_t *lastValidRenderer = ri.Cvar_Get( "r_lastValidRenderer", "(uninitialized)", CVAR_ARCHIVE );
	cvar_t	*cv;

	ri.Printf( PRINT_ALL, "Initializing OpenGL subsystem\n" );

	//
	// check OS version to see if we can do fullscreen display changes
	//
	if ( !GLW_CheckOSVersion() )
	{
		ri.Error( ERR_FATAL, "GLimp_Init() - incorrect operating system\n" );
	}

	// save off hInstance and wndproc
	cv = ri.Cvar_Get( "win_hinstance", "", 0 );
	sscanf( cv->string, "%i", (int *)&g_wv.hInstance );

	cv = ri.Cvar_Get( "win_wndproc", "", 0 );
	sscanf( cv->string, "%i", (int *)&glw_state.wndproc );

	r_allowSoftwareGL = ri.Cvar_Get( "r_allowSoftwareGL", "0", CVAR_LATCH );
	r_maskMinidriver = ri.Cvar_Get( "r_maskMinidriver", "0", CVAR_LATCH );

	// load appropriate DLL and initialize subsystem
	GLW_StartOpenGL();

	// get our config strings
	Q_strncpyz( glConfig.vendor_string, qglGetString (GL_VENDOR), sizeof( glConfig.vendor_string ) );
	Q_strncpyz( glConfig.renderer_string, qglGetString (GL_RENDERER), sizeof( glConfig.renderer_string ) );
	Q_strncpyz( glConfig.version_string, qglGetString (GL_VERSION), sizeof( glConfig.version_string ) );
	Q_strncpyz( glConfig.extensions_string, qglGetString (GL_EXTENSIONS), sizeof( glConfig.extensions_string ) );

	//
	// chipset specific configuration
	//
	Q_strncpyz( buf, glConfig.renderer_string, sizeof(buf) );
	Q_strlwr( buf );

	//
	// NOTE: if changing cvars, do it within this block.  This allows them
	// to be overridden when testing driver fixes, etc. but only sets
	// them to their default state when the hardware is first installed/run.
	//
	if ( Q_stricmp( lastValidRenderer->string, glConfig.renderer_string ) )
	{
		glConfig.hardwareType = GLHW_GENERIC;

		ri.Cvar_Set( "r_textureMode", "GL_LINEAR_MIPMAP_NEAREST" );

		// VOODOO GRAPHICS w/ 2MB
		if ( strstr( buf, "voodoo graphics/1 tmu/2 mb" ) )
		{
			ri.Cvar_Set( "r_picmip", "2" );
			ri.Cvar_Get( "r_picmip", "1", CVAR_ARCHIVE | CVAR_LATCH );
		}
		else
		{
			ri.Cvar_Set( "r_picmip", "1" );

			if ( strstr( buf, "rage 128" ) || strstr( buf, "rage128" ) )
			{
				ri.Cvar_Set( "r_finish", "0" );
			}
			// Savage3D and Savage4 should always have trilinear enabled
			else if ( strstr( buf, "savage3d" ) || strstr( buf, "s3 savage4" ) )
			{
				ri.Cvar_Set( "r_texturemode", "GL_LINEAR_MIPMAP_LINEAR" );
			}
		}
	}
	
	//
	// this is where hardware specific workarounds that should be
	// detected/initialized every startup should go.
	//
	if ( strstr( buf, "banshee" ) || strstr( buf, "voodoo3" ) )
	{
		glConfig.hardwareType = GLHW_3DFX_2D3D;
	}
	// VOODOO GRAPHICS w/ 2MB
	else if ( strstr( buf, "voodoo graphics/1 tmu/2 mb" ) )
	{
	}
	else if ( strstr( buf, "glzicd" ) )
	{
	}
	else if ( strstr( buf, "rage pro" ) || strstr( buf, "Rage Pro" ) || strstr( buf, "ragepro" ) )
	{
		glConfig.hardwareType = GLHW_RAGEPRO;
	}
	else if ( strstr( buf, "rage 128" ) )
	{
	}
	else if ( strstr( buf, "permedia2" ) )
	{
		glConfig.hardwareType = GLHW_PERMEDIA2;
	}
	else if ( strstr( buf, "riva 128" ) )
	{
		glConfig.hardwareType = GLHW_RIVA128;
	}
	else if ( strstr( buf, "riva tnt " ) )
	{
	}

	ri.Cvar_Set( "r_lastValidRenderer", glConfig.renderer_string );

	GLW_InitExtensions();
	WG_CheckHardwareGamma();
}
Beispiel #21
0
/*
====================
CL_Record_f

record <slot> [<demoname>]

Begins recording a demo from the current position
====================
*/
void CL_Record( client_t	*cl, char *s ) {
	char		name[MAX_OSPATH];
	char		name_zip[MAX_OSPATH];
	byte		bufData[MAX_MSGLEN];
	msg_t	buf;
	int			i;
	int			len;
	entityState_t	*ent;
	entityState_t	nullstate;
	int         clientnum;
	char	*guid;
	char	prefix[MAX_OSPATH];

	clientnum = cl - svs.clients;

	if ( cl->demorecording ) {
		Com_Printf ("Already recording client %i.\n", clientnum);
		return;
	}

//	if ( cl->state != CA_ACTIVE ) {
//		Com_Printf ("You must be in a level to record.\n");
//		return;
//	}
//  // sync 0 doesn't prevent recording, so not forcing it off .. everyone does g_sync 1 ; record ; g_sync 0 ..
//	if ( NET_IsLocalAddress( cl->serverAddress ) && !Cvar_VariableValue( "g_synchronousClients" ) ) {
//		Com_Printf (S_COLOR_YELLOW "WARNING: You should set 'g_synchronousClients 1' for smoother demo recording\n");
//	}

	if ( s ) {
		Com_sprintf (name, sizeof(name), "demos/%s.dm_%d", s, PROTOCOL_VERSION );
	} else {
		int		number,n,a,b,c,d;
		guid = Info_ValueForKey(cl->userinfo, "cl_guid");
		if (!Q_stricmp(guid, "")) {
			guid = "LONGGONE";
		}
		Q_strncpyz(prefix, guid, 9);

		// scan for a free demo name
		for ( number = 0 ; number <= 9999 ; number++ ) {
			if(number < 0 || number > 9999)
				number = 9999;
			n = number;
			a = n / 1000;
			n -= a*1000;
			b = n / 100;
			n -= b*100;
			c = n / 10;
			n -= c*10;
			d = n;

			Com_sprintf (name, sizeof(name), "demos/%s_%s_%i%i%i%i.dm_%d", prefix, sv_mapname->string, a, b, c, d, PROTOCOL_VERSION );
			Com_sprintf (name_zip, sizeof(name_zip), "demos/%s_%s_%i%i%i%i.dm_%d.zip", prefix, sv_mapname->string, a, b, c, d, PROTOCOL_VERSION );
			Q_strlwr(name);
			Q_strlwr(name_zip);
			if (!FS_FileExists(name) && !FS_FileExists(name_zip)) {
				break;	// file doesn't exist
			}
		}
	}

	// open the demo file

	if (!sv_autorecord->integer) {
		Com_Printf ("recording client %i to %s.\n", clientnum, name);
	} else {
		Com_Printf ("Record: %i: %s\n", clientnum, name);
	}

	cl->demofile = FS_FOpenFileWrite( name );
	if ( !cl->demofile ) {
		Com_Printf ("ERROR: couldn't open.\n");
		return;
	}
	// don't start saving messages until a non-delta compressed message is received
	cl->demowaiting = qtrue;
	cl->savedemo = qfalse; // demo will not be saved if sv_autorecord 1 and cl's score is too low

	Q_strncpyz( cl->demoName, name, sizeof( cl->demoName ) );

	// write out the gamestate message
	MSG_Init (&buf, bufData, sizeof(bufData));
	MSG_Bitstream(&buf);

	// NOTE, MRE: all server->client messages now acknowledge
	MSG_WriteLong( &buf, cl->lastClientCommand );// 0007 - 000A

	MSG_WriteByte (&buf, svc_gamestate);// 000B
	MSG_WriteLong (&buf, cl->reliableSequence );// 000C - 000F


	// write the configstrings
	for ( i = 0 ; i < MAX_CONFIGSTRINGS ; i++ ) {
		if (sv.configstrings[i][0]) {
			MSG_WriteByte( &buf, svc_configstring );
			MSG_WriteShort( &buf, i );
			MSG_WriteBigString( &buf, sv.configstrings[i] );
		}
	}

	// write the baselines
	Com_Memset( &nullstate, 0, sizeof( nullstate ) );
	for ( i = 0 ; i < MAX_GENTITIES; i++ ) {
		ent = &sv.svEntities[i].baseline;
		if ( !ent->number ) {
			continue;
		}
		MSG_WriteByte( &buf, svc_baseline );
		MSG_WriteDeltaEntity( &buf, &nullstate, ent, qtrue );
	}

	MSG_WriteByte( &buf, svc_EOF );

	// finished writing the gamestate stuff

	// write the client num
	MSG_WriteLong(&buf, clientnum);
	// write the checksum feed
	MSG_WriteLong(&buf, sv.checksumFeed);

	// finished writing the client packet
	MSG_WriteByte( &buf, svc_EOF );

	// write it to the demo file
	len = LittleLong( cl->netchan.outgoingSequence-1 );
	FS_Write (&len, 4, cl->demofile);// 0000 - 0003

	len = LittleLong (buf.cursize);
	FS_Write (&len, 4, cl->demofile);// 0004 - 0007
	FS_Write (buf.data, buf.cursize, cl->demofile);// 0007 - ...

	// the rest of the demo file will be copied from net messages
	cl->demorecording = qtrue;
}
Beispiel #22
0
/*
* CL_InitDownload_f
* 
* Hanldles server's initdownload message, starts web or server download if possible
*/
 static void CL_InitDownload_f( void )
{
	const char *filename;
	const char *url;
	int size, alloc_size;
	unsigned checksum;
	qboolean allow_localhttpdownload;
	download_list_t	*dl;
	// ignore download commands coming from demo files
	if( cls.demo.playing )		
		return;

	// read the data
	filename = Cmd_Argv( 1 );
	size = atoi( Cmd_Argv( 2 ) );
	checksum = strtoul( Cmd_Argv( 3 ), NULL, 10 );
	allow_localhttpdownload = ( atoi( Cmd_Argv( 4 ) ) != 0 ) && cls.httpbaseurl != NULL;
	url = Cmd_Argv( 5 );

	if( !cls.download.requestname )
	{
		Com_Printf( "Got init download message without request\n" );
		return;
	}

	if( cls.download.filenum || cls.download.web )
	{
		Com_Printf( "Got init download message while already downloading\n" );
		return;
	}

	if( size == -1 )
	{
		// means that download was refused
		Com_Printf( "Server refused download request: %s\n", url ); // if it's refused, url field holds the reason
		CL_DownloadDone();
		return;
	}

	if( size <= 0 )
	{
		Com_Printf( "Server gave invalid size, not downloading\n" );
		CL_DownloadDone();
		return;
	}

	if( checksum == 0 )
	{
		Com_Printf( "Server didn't provide checksum, not downloading\n" );
		CL_DownloadDone();
		return;
	}

	if( !COM_ValidateRelativeFilename( filename ) )
	{
		Com_Printf( "Not downloading, invalid filename: %s\n", filename );
		CL_DownloadDone();
		return;
	}

	if( FS_CheckPakExtension( filename ) && !cls.download.requestpak )
	{
		Com_Printf( "Got a pak file when requesting normal one, not downloading\n" );
		CL_DownloadDone();
		return;
	}

	if( !FS_CheckPakExtension( filename ) && cls.download.requestpak )
	{
		Com_Printf( "Got a non pak file when requesting pak, not downloading\n" );
		CL_DownloadDone();
		return;
	}

	if( !strchr( filename, '/' ) )
	{
		Com_Printf( "Refusing to download file with no gamedir: %s\n", filename );
		CL_DownloadDone();
		return;
	}

	// check that it is in game or basegame dir
	if( strlen( filename ) < strlen( FS_GameDirectory() )+1 ||
		strncmp( filename, FS_GameDirectory(), strlen( FS_GameDirectory() ) ) ||
		filename[strlen( FS_GameDirectory() )] != '/' )
	{
		if( strlen( filename ) < strlen( FS_BaseGameDirectory() )+1 ||
			strncmp( filename, FS_BaseGameDirectory(), strlen( FS_BaseGameDirectory() ) ) ||
			filename[strlen( FS_BaseGameDirectory() )] != '/' )
		{
			Com_Printf( "Can't download, invalid game directory: %s\n", filename );
			CL_DownloadDone();
			return;
		}
	}

	if( FS_CheckPakExtension( filename ) )
	{
		if( strchr( strchr( filename, '/' ) + 1, '/' ) )
		{
			Com_Printf( "Refusing to download pack file to subdirectory: %s\n", filename );
			CL_DownloadDone();
			return;
		}

		if( !Q_strnicmp( COM_FileBase( filename ), "modules", strlen( "modules" ) ) )
		{
			if( !CL_CanDownloadModules() )
			{
				CL_DownloadDone();
				return;
			}
		}

		if( FS_FOpenBaseFile( filename, NULL, FS_READ ) != -1 )
		{
			Com_Printf( "Can't download, file already exists: %s\n", filename );
			CL_DownloadDone();
			return;
		}
	}
	else
	{
		if( strcmp( cls.download.requestname, strchr( filename, '/' ) + 1 ) )
		{
			Com_Printf( "Can't download, got different file than requested: %s\n", filename );
			CL_DownloadDone();
			return;
		}
	}

	if( cls.download.requestnext )
	{
		dl = cls.download.list;
		while( dl != NULL )
		{
			if( !Q_stricmp( dl->filename, filename ) )
			{
				Com_Printf( "Skipping, already tried downloading: %s\n", filename );
				CL_DownloadDone();
				return;
			}
			dl = dl->next;
		}
	}

	cls.download.name = ZoneCopyString( filename );

	alloc_size = strlen( filename ) + strlen( ".tmp" ) + 1;
	cls.download.tempname = Mem_ZoneMalloc( alloc_size );
	Q_snprintfz( cls.download.tempname, alloc_size, "%s.tmp", filename );

	cls.download.web = qfalse;
	cls.download.cancelled = qfalse;
	cls.download.disconnect = qfalse;
	cls.download.size = size;
	cls.download.checksum = checksum;
	cls.download.percent = 0;
	cls.download.timeout = 0;
	cls.download.retries = 0;
	cls.download.timestart = Sys_Milliseconds();
	cls.download.offset = 0;
	cls.download.baseoffset = 0;
	cls.download.pending_reconnect = qfalse;

	Cvar_ForceSet( "cl_download_name", COM_FileBase( cls.download.name ) );
	Cvar_ForceSet( "cl_download_percent", "0" );

	if( cls.download.requestnext )
	{
		dl = Mem_ZoneMalloc( sizeof( download_list_t ) );
		dl->filename = ZoneCopyString( cls.download.name );
		dl->next = cls.download.list;
		cls.download.list = dl;
	}

	if( cl_downloads_from_web->integer && allow_localhttpdownload && url && url[0] != 0 ) {
		cls.download.web = qtrue;
		Com_Printf( "Web download: %s from %s%s\n", cls.download.tempname, cls.httpbaseurl, url );
	}
	else if( cl_downloads_from_web->integer && url && url[0] != 0 ) {
		cls.download.web = qtrue;
		Com_Printf( "Web download: %s from %s\n", cls.download.tempname, url );
	}
	else {
		Com_Printf( "Server download: %s\n", cls.download.tempname );
	}

	cls.download.baseoffset = cls.download.offset = FS_FOpenBaseFile( cls.download.tempname, &cls.download.filenum, FS_APPEND );
	if( !cls.download.filenum )
	{
		Com_Printf( "Can't download, couldn't open %s for writing\n", cls.download.tempname );

		Mem_ZoneFree( cls.download.name );
		cls.download.name = NULL;
		Mem_ZoneFree( cls.download.tempname );
		cls.download.tempname = NULL;

		cls.download.filenum = 0;
		cls.download.offset = 0;
		cls.download.size = 0;
		CL_DownloadDone();
		return;
	}

	if( cls.download.web ) {
		char *referer, *fullurl;
		const char *headers[] = { NULL, NULL, NULL, NULL, NULL, NULL, NULL };

		alloc_size = strlen( APP_URI_SCHEME ) + strlen( NET_AddressToString( &cls.serveraddress ) ) + 1;
		referer = Mem_ZoneMalloc( alloc_size );
		Q_snprintfz( referer, alloc_size, APP_URI_SCHEME "%s", NET_AddressToString( &cls.serveraddress ) );
		Q_strlwr( referer );

		if( allow_localhttpdownload ) {
			alloc_size = strlen( cls.httpbaseurl ) + 1 + strlen( url ) + 1;
			fullurl = Mem_ZoneMalloc( alloc_size );
			Q_snprintfz( fullurl, alloc_size, "%s/%s", cls.httpbaseurl, url );
		}
		else {
			size_t url_len = strlen( url );
			alloc_size = url_len + 1 + strlen( filename ) * 3 + 1;
			fullurl = Mem_ZoneMalloc( alloc_size );
			Q_snprintfz( fullurl, alloc_size, "%s/", url );
			Q_urlencode_unsafechars( filename, fullurl + url_len + 1, alloc_size - url_len - 1 );
		}

		headers[0] = "Referer";
		headers[1] = referer;

		CL_AddSessionHttpRequestHeaders( fullurl, &headers[2] );

		CL_AsyncStreamRequest( fullurl, headers, cl_downloads_from_web_timeout->integer / 100, cls.download.offset, 
			CL_WebDownloadReadCb, CL_WebDownloadDoneCb, NULL, NULL, qfalse );

		Mem_ZoneFree( fullurl );
		Mem_ZoneFree( referer );
		return;
	}

	// have to use Sys_Milliseconds because cls.realtime might be old from Web_Get
	cls.download.timeout = Sys_Milliseconds() + 3000;
	cls.download.retries = 0;

	CL_AddReliableCommand( va( "nextdl \"%s\" %i", cls.download.name, cls.download.offset ) );
}
Beispiel #23
0
/*
=================
R_LoadMD3
=================
*/
static qboolean R_LoadMD3 (model_t *mod, int lod, void *buffer, const char *mod_name, qboolean &bAlreadyCached ) {
	int					i, j;
	md3Header_t			*pinmodel;
	md3Surface_t		*surf;
	md3Shader_t			*shader;
	int					version;
	int					size;

#ifdef Q3_BIG_ENDIAN
	md3Frame_t			*frame;
	md3Triangle_t		*tri;
	md3St_t				*st;
	md3XyzNormal_t		*xyz;
	md3Tag_t			*tag;
#endif


	pinmodel= (md3Header_t *)buffer;
	//
	// read some fields from the binary, but only LittleLong() them when we know this wasn't an already-cached model...
	//
	version = pinmodel->version;
	size	= pinmodel->ofsEnd;

	if (!bAlreadyCached)
	{
		version = LittleLong(version);
		size	= LittleLong(size);
	}

	if (version != MD3_VERSION) {
		ri.Printf( PRINT_WARNING, "R_LoadMD3: %s has wrong version (%i should be %i)\n",
				 mod_name, version, MD3_VERSION);
		return qfalse;
	}

	mod->type      = MOD_MESH;
	mod->dataSize += size;

	qboolean bAlreadyFound = qfalse;
	mod->md3[lod] = (md3Header_t *) RE_RegisterModels_Malloc(size, buffer, mod_name, &bAlreadyFound, TAG_MODEL_MD3);

	assert(bAlreadyCached == bAlreadyFound);

	if (!bAlreadyFound)
	{
		// horrible new hackery, if !bAlreadyFound then we've just done a tag-morph, so we need to set the
		//	bool reference passed into this function to true, to tell the caller NOT to do an FS_Freefile since
		//	we've hijacked that memory block...
		//
		// Aaaargh. Kill me now...
		//
		bAlreadyCached = qtrue;
		assert( mod->md3[lod] == buffer );
//		memcpy( mod->md3[lod], buffer, size );	// and don't do this now, since it's the same thing

		LL(mod->md3[lod]->ident);
		LL(mod->md3[lod]->version);
		LL(mod->md3[lod]->numFrames);
		LL(mod->md3[lod]->numTags);
		LL(mod->md3[lod]->numSurfaces);
		LL(mod->md3[lod]->ofsFrames);
		LL(mod->md3[lod]->ofsTags);
		LL(mod->md3[lod]->ofsSurfaces);
		LL(mod->md3[lod]->ofsEnd);
	}

	if ( mod->md3[lod]->numFrames < 1 ) {
		ri.Printf( PRINT_WARNING, "R_LoadMD3: %s has no frames\n", mod_name );
		return qfalse;
	}

	if (bAlreadyFound)
	{
		return qtrue;	// All done. Stop, go no further, do not pass Go...
	}

#ifdef Q3_BIG_ENDIAN
	// swap all the frames
	frame = (md3Frame_t *) ( (byte *)mod->md3[lod] + mod->md3[lod]->ofsFrames );
	for ( i = 0 ; i < mod->md3[lod]->numFrames ; i++, frame++) {
		LF(frame->radius);
		for ( j = 0 ; j < 3 ; j++ ) {
			LF(frame->bounds[0][j]);
			LF(frame->bounds[1][j]);
			LF(frame->localOrigin[j]);
		}
	}

	// swap all the tags
	tag = (md3Tag_t *) ( (byte *)mod->md3[lod] + mod->md3[lod]->ofsTags );
	for ( i = 0 ; i < mod->md3[lod]->numTags * mod->md3[lod]->numFrames ; i++, tag++) {
		for ( j = 0 ; j < 3 ; j++ ) {
			LF(tag->origin[j]);
			LF(tag->axis[0][j]);
			LF(tag->axis[1][j]);
			LF(tag->axis[2][j]);
		}
	}
#endif

	// swap all the surfaces
	surf = (md3Surface_t *) ( (byte *)mod->md3[lod] + mod->md3[lod]->ofsSurfaces );
	for ( i = 0 ; i < mod->md3[lod]->numSurfaces ; i++) {
        LL(surf->flags);
        LL(surf->numFrames);
        LL(surf->numShaders);
        LL(surf->numTriangles);
        LL(surf->ofsTriangles);
        LL(surf->numVerts);
        LL(surf->ofsShaders);
        LL(surf->ofsSt);
        LL(surf->ofsXyzNormals);
        LL(surf->ofsEnd);

		if ( surf->numVerts > SHADER_MAX_VERTEXES ) {
			Com_Error (ERR_DROP, "R_LoadMD3: %s has more than %i verts on a surface (%i)",
				mod_name, SHADER_MAX_VERTEXES, surf->numVerts );
		}
		if ( surf->numTriangles*3 > SHADER_MAX_INDEXES ) {
			Com_Error (ERR_DROP, "R_LoadMD3: %s has more than %i triangles on a surface (%i)",
				mod_name, SHADER_MAX_INDEXES / 3, surf->numTriangles );
		}

		// change to surface identifier
		surf->ident = SF_MD3;

		// lowercase the surface name so skin compares are faster
		Q_strlwr( surf->name );

		// strip off a trailing _1 or _2
		// this is a crutch for q3data being a mess
		j = strlen( surf->name );
		if ( j > 2 && surf->name[j-2] == '_' ) {
			surf->name[j-2] = 0;
		}

        // register the shaders
        shader = (md3Shader_t *) ( (byte *)surf + surf->ofsShaders );
        for ( j = 0 ; j < surf->numShaders ; j++, shader++ ) {
            shader_t	*sh;

            sh = R_FindShader( shader->name, lightmapsNone, stylesDefault, qtrue );
			if ( sh->defaultShader ) {
				shader->shaderIndex = 0;
			} else {
				shader->shaderIndex = sh->index;
			}
			RE_RegisterModels_StoreShaderRequest(mod_name, &shader->name[0], &shader->shaderIndex);
        }


#ifdef Q3_BIG_ENDIAN
		// swap all the triangles
		tri = (md3Triangle_t *) ( (byte *)surf + surf->ofsTriangles );
		for ( j = 0 ; j < surf->numTriangles ; j++, tri++ ) {
			LL(tri->indexes[0]);
			LL(tri->indexes[1]);
			LL(tri->indexes[2]);
		}

		// swap all the ST
		st = (md3St_t *) ( (byte *)surf + surf->ofsSt );
		for ( j = 0 ; j < surf->numVerts ; j++, st++ ) {
			LF(st->st[0]);
			LF(st->st[1]);
		}

		// swap all the XyzNormals
		xyz = (md3XyzNormal_t *) ( (byte *)surf + surf->ofsXyzNormals );
		for ( j = 0 ; j < surf->numVerts * surf->numFrames ; j++, xyz++ )
		{
			LS(xyz->xyz[0]);
			LS(xyz->xyz[1]);
			LS(xyz->xyz[2]);

			LS(xyz->normal);
		}
#endif

		// find the next surface
		surf = (md3Surface_t *)( (byte *)surf + surf->ofsEnd );
	}

	return qtrue;
}
/*
** GLimp_Init
**
** This is the platform specific OpenGL initialization function.  It
** is responsible for loading OpenGL, initializing it, setting
** extensions, creating a window of the appropriate size, doing
** fullscreen manipulations, etc.  Its overall responsibility is
** to make sure that a functional OpenGL subsystem is operating
** when it returns to the ref.
*/
void GLimp_Init( void )
{
	char	buf[1024];
	cvar_t *lastValidRenderer = ri.Cvar_Get( "r_lastValidRenderer", "(uninitialized)", CVAR_ARCHIVE );
	cvar_t	*cv;

	ri.Printf( PRINT_ALL, "Initializing OpenGL subsystem\n" );

	GLW_CheckForBustedDrivers();

	r_allowSoftwareGL = ri.Cvar_Get( "r_allowSoftwareGL", "0", CVAR_LATCH );

	// save off hInstance and wndproc
	cv = ri.Cvar_Get( "win_hinstance", "", 0 );
	sscanf( cv->string, "%i", (int*)&((WinVars_t*)ri.PlatformGetVars())->hInstance ); //FixMe: this is NOT 64-bit safe

	cv = ri.Cvar_Get( "win_wndproc", "", 0 );
	sscanf( cv->string, "%i", (int*)&glw_state.wndproc ); //FixMe: this is NOT 64-bit safe

	GLW_GetDisplayModes();

	r_mode = ri.Cvar_Get( "r_mode", "4", CVAR_ARCHIVE | CVAR_LATCH );
	r_fullscreen = ri.Cvar_Get( "r_fullscreen", "0", CVAR_ARCHIVE | CVAR_LATCH );
	
	r_fsmonitor = ri.Cvar_Get( "r_fsmonitor", GLW_GetDefaultFSMonitor(), CVAR_ARCHIVE | CVAR_LATCH );	
	GLW_ValidateFSMonitorCvar();

	r_fsmode = ri.Cvar_Get( "r_fsmode", GLW_GetDefaultFSMode( r_fsmonitor->string ), CVAR_ARCHIVE | CVAR_LATCH );
	GLW_ValidateFSModeCvar();

	GLW_CreateGLWnd();

	ri.Cmd_AddCommand( "vid_fsUseCurMon", GLW_UseCurrentMonitor );

	// get our config strings
	Q_strncpyz( glConfig.vendor_string, (const char*)glGetString( GL_VENDOR ), sizeof( glConfig.vendor_string ) );
	Q_strncpyz( glConfig.renderer_string, (const char*)glGetString( GL_RENDERER ), sizeof( glConfig.renderer_string ) );
	Q_strncpyz( glConfig.version_string, (const char*)glGetString( GL_VERSION ), sizeof( glConfig.version_string ) );
	Q_strncpyz( glConfig.extensions_string, (const char*)glGetString( GL_EXTENSIONS ), sizeof( glConfig.extensions_string ) );

	//
	// chipset specific configuration
	//
	Q_strncpyz( buf, glConfig.renderer_string, sizeof(buf) );
	Q_strlwr( buf );

	//
	// NOTE: if changing cvars, do it within this block.  This allows them
	// to be overridden when testing driver fixes, etc. but only sets
	// them to their default state when the hardware is first installed/run.
	//
	if( Q_stricmp( lastValidRenderer->string, glConfig.renderer_string ) )
		ri.Cvar_Set( "r_textureMode", "LinearMipLinear" );
	
	//
	// this is where hardware specific workarounds that should be
	// detected/initialized every startup should go.
	//

	/*
	if( strstr( buf, "banshee" ) || strstr( buf, "voodoo3" ) )
		;
	else if( strstr( buf, "voodoo graphics/1 tmu/2 mb" ) )
		;
	else if( strstr( buf, "glzicd" ) )
		;
	else if( strstr( buf, "rage pro" ) || strstr( buf, "Rage Pro" ) || strstr( buf, "ragepro" ) )
		;
	else if( strstr( buf, "rage 128" ) )
		;
	else if( strstr( buf, "permedia2" ) )
		;
	else if( strstr( buf, "riva 128" ) )
		;
	else if( strstr( buf, "riva tnt " ) )
		;
	*/

	ri.Cvar_Set( "r_lastValidRenderer", glConfig.renderer_string );

	GLW_InitExtensions();

	glimp_suspendRender = false;
}
Beispiel #25
0
static qboolean R_LoadMDR( model_t *mod, void *buffer, int filesize, const char *mod_name ) 
{
	int					i, j, k, l;
	mdrHeader_t			*pinmodel, *mdr;
        mdrFrame_t			*frame;
	mdrLOD_t			*lod, *curlod;
	mdrSurface_t			*surf, *cursurf;
	mdrTriangle_t			*tri, *curtri;
	mdrVertex_t			*v, *curv;
	mdrWeight_t			*weight, *curweight;
	mdrTag_t			*tag, *curtag;
	int					size;
	shader_t			*sh;

	pinmodel = (mdrHeader_t *)buffer;

	pinmodel->version = LittleLong(pinmodel->version);
	if (pinmodel->version != MDR_VERSION) 
	{
		ri.Printf(PRINT_WARNING, "R_LoadMDR: %s has wrong version (%i should be %i)\n", mod_name, pinmodel->version, MDR_VERSION);
		return qfalse;
	}

	size = LittleLong(pinmodel->ofsEnd);
	
	if(size > filesize)
	{
		ri.Printf(PRINT_WARNING, "R_LoadMDR: Header of %s is broken. Wrong filesize declared!\n", mod_name);
		return qfalse;
	}
	
	mod->type = MOD_MDR;

	pinmodel->numFrames = LittleLong(pinmodel->numFrames);
	pinmodel->numBones = LittleLong(pinmodel->numBones);
	pinmodel->ofsFrames = LittleLong(pinmodel->ofsFrames);
	
	// This is a model that uses some type of compressed Bones. We don't want to uncompress every bone for each rendered frame
	// over and over again, we'll uncompress it in this function already, so we must adjust the size of the target md4.
	if(pinmodel->ofsFrames < 0)
	{
		// mdrFrame_t is larger than mdrCompFrame_t:
		size += pinmodel->numFrames * sizeof(frame->name);
		// now add enough space for the uncompressed bones.
		size += pinmodel->numFrames * pinmodel->numBones * ((sizeof(mdrBone_t) - sizeof(mdrCompBone_t)));
	}
	
	mod->dataSize += size;
	mod->md4 = mdr = ri.Hunk_Alloc( size, h_low );

	// Copy all the values over from the file and fix endian issues in the process, if necessary.
	
	mdr->ident = LittleLong(pinmodel->ident);
	mdr->version = pinmodel->version;	// Don't need to swap byte order on this one, we already did above.
	strlcpy(mdr->name, pinmodel->name, sizeof(mdr->name));
	mdr->numFrames = pinmodel->numFrames;
	mdr->numBones = pinmodel->numBones;
	mdr->numLODs = LittleLong(pinmodel->numLODs);
	mdr->numTags = LittleLong(pinmodel->numTags);
	// We don't care about offset values, we'll generate them ourselves while loading.
	
	mod->numLods = mdr->numLODs;

	if ( mdr->numFrames < 1 ) 
	{
		ri.Printf(PRINT_WARNING, "R_LoadMDR: %s has no frames\n", mod_name);
		return qfalse;
	}

	/* The first frame will be put into the first free space after the header */
	frame = (mdrFrame_t *)(mdr + 1);
	mdr->ofsFrames = (int)((byte *) frame - (byte *) mdr);
		
	if (pinmodel->ofsFrames < 0)
	{
		mdrCompFrame_t *cframe;
				
		// compressed model...				
		cframe = (mdrCompFrame_t *)((byte *) pinmodel - pinmodel->ofsFrames);

		for(i = 0; i < mdr->numFrames; i++)
		{
			for(j = 0; j < 3; j++)
			{
				frame->bounds[0][j] = LittleFloat(cframe->bounds[0][j]);
				frame->bounds[1][j] = LittleFloat(cframe->bounds[1][j]);
				frame->localOrigin[j] = LittleFloat(cframe->localOrigin[j]);
			}

			frame->radius = LittleFloat(cframe->radius);
			frame->name[0] = '\0';	// No name supplied in the compressed version.
			
			for(j = 0; j < mdr->numBones; j++)
			{
				for(k = 0; k < (sizeof(cframe->bones[j].Comp) / 2); k++)
				{
					// Do swapping for the uncompressing functions. They seem to use shorts
					// values only, so I assume this will work. Never tested it on other
					// platforms, though.
					
					((unsigned short *)(cframe->bones[j].Comp))[k] =
						LittleShort( ((unsigned short *)(cframe->bones[j].Comp))[k] );
				}
				
				/* Now do the actual uncompressing */
				MC_UnCompress(frame->bones[j].matrix, cframe->bones[j].Comp);
			}
			
			// Next Frame...
			cframe = (mdrCompFrame_t *) &cframe->bones[j];
			frame = (mdrFrame_t *) &frame->bones[j];
		}
	}
	else
	{
		mdrFrame_t *curframe;
		
		// uncompressed model...
		//
    
		curframe = (mdrFrame_t *)((byte *) pinmodel + pinmodel->ofsFrames);
		
		// swap all the frames
		for ( i = 0 ; i < mdr->numFrames ; i++) 
		{
			for(j = 0; j < 3; j++)
			{
				frame->bounds[0][j] = LittleFloat(curframe->bounds[0][j]);
				frame->bounds[1][j] = LittleFloat(curframe->bounds[1][j]);
				frame->localOrigin[j] = LittleFloat(curframe->localOrigin[j]);
			}
			
			frame->radius = LittleFloat(curframe->radius);
			strlcpy(frame->name, curframe->name, sizeof(frame->name));
			
			for (j = 0; j < (int) (mdr->numBones * sizeof(mdrBone_t) / 4); j++) 
			{
				((float *)frame->bones)[j] = LittleFloat( ((float *)curframe->bones)[j] );
			}
			
			curframe++;
			frame++;
		}
	}
	
	// frame should now point to the first free address after all frames.
	lod = (mdrLOD_t *) frame;
	mdr->ofsLODs = (int) ((byte *) lod - (byte *)mdr);
	
	curlod = (mdrLOD_t *)((byte *) pinmodel + LittleLong(pinmodel->ofsLODs));
		
	// swap all the LOD's
	for ( l = 0 ; l < mdr->numLODs ; l++)
	{
		lod->numSurfaces = LittleLong(curlod->numSurfaces);
		
		// swap all the surfaces
		surf = (mdrSurface_t *) (lod + 1);
		lod->ofsSurfaces = (int)((byte *) surf - (byte *) lod);
		cursurf = (mdrSurface_t *) ((byte *)curlod + LittleLong(curlod->ofsSurfaces));
		
		for ( i = 0 ; i < lod->numSurfaces ; i++) {
			// first do some copying stuff
			
			surf->ident = SF_MDR;
			strlcpy(surf->name, cursurf->name, sizeof(surf->name));
			strlcpy(surf->shader, cursurf->shader, sizeof(surf->shader));
			
			surf->ofsHeader = (byte *) mdr - (byte *) surf;
			
			surf->numVerts = LittleLong(cursurf->numVerts);
			surf->numTriangles = LittleLong(cursurf->numTriangles);
			// numBoneReferences and BoneReferences generally seem to be unused
			
			// now do the checks that may fail.
			if ( surf->numVerts > SHADER_MAX_VERTEXES ) 
			{
				ri.Printf(PRINT_WARNING, "R_LoadMDR: %s has more than %i verts on a surface (%i)",
					  mod_name, SHADER_MAX_VERTEXES, surf->numVerts );
				return qfalse;
			}
			if ( surf->numTriangles*3 > SHADER_MAX_INDEXES ) 
			{
				ri.Printf(PRINT_WARNING, "R_LoadMDR: %s has more than %i triangles on a surface (%i)",
					  mod_name, SHADER_MAX_INDEXES / 3, surf->numTriangles );
				return qfalse;
			}
			// lowercase the surface name so skin compares are faster
			Q_strlwr( surf->name );

			// register the shaders
			sh = R_FindShader(surf->shader, LIGHTMAP_NONE, qtrue);
			if ( sh->defaultShader ) {
				surf->shaderIndex = 0;
			} else {
				surf->shaderIndex = sh->index;
			}
			
			// now copy the vertexes.
			v = (mdrVertex_t *) (surf + 1);
			surf->ofsVerts = (int)((byte *) v - (byte *) surf);
			curv = (mdrVertex_t *) ((byte *)cursurf + LittleLong(cursurf->ofsVerts));
			
			for(j = 0; j < surf->numVerts; j++)
			{
				v->normal[0] = LittleFloat(curv->normal[0]);
				v->normal[1] = LittleFloat(curv->normal[1]);
				v->normal[2] = LittleFloat(curv->normal[2]);
				
				v->texCoords[0] = LittleFloat(curv->texCoords[0]);
				v->texCoords[1] = LittleFloat(curv->texCoords[1]);
				
				v->numWeights = LittleLong(curv->numWeights);
				weight = &v->weights[0];
				curweight = &curv->weights[0];
				
				// Now copy all the weights
				for(k = 0; k < v->numWeights; k++)
				{
					weight->boneIndex = LittleLong(curweight->boneIndex);
					weight->boneWeight = LittleFloat(curweight->boneWeight);
					
					weight->offset[0] = LittleFloat(curweight->offset[0]);
					weight->offset[1] = LittleFloat(curweight->offset[1]);
					weight->offset[2] = LittleFloat(curweight->offset[2]);
					
					weight++;
					curweight++;
				}
				
				v = (mdrVertex_t *) weight;
				curv = (mdrVertex_t *) curweight;
			}
						
			// we know the offset to the triangles now:
			tri = (mdrTriangle_t *) v;
			surf->ofsTriangles = (int)((byte *) tri - (byte *) surf);
			curtri = (mdrTriangle_t *)((byte *) cursurf + LittleLong(cursurf->ofsTriangles));
			
			for(j = 0; j < surf->numTriangles; j++)
			{
				tri->indexes[0] = LittleLong(curtri->indexes[0]);
				tri->indexes[1] = LittleLong(curtri->indexes[1]);
				tri->indexes[2] = LittleLong(curtri->indexes[2]);
				
				tri++;
				curtri++;
			}
			
			// tri now points to the end of the surface.
			surf->ofsEnd = (byte *) tri - (byte *) surf;
			surf = (mdrSurface_t *) tri;

			// find the next surface.
			cursurf = (mdrSurface_t *) ((byte *) cursurf + LittleLong(cursurf->ofsEnd));
		}

		// surf points to the next lod now.
		lod->ofsEnd = (int)((byte *) surf - (byte *) lod);
		lod = (mdrLOD_t *) surf;

		// find the next LOD.
		curlod = (mdrLOD_t *)((byte *) curlod + LittleLong(curlod->ofsEnd));
	}
	
	// lod points to the first tag now, so update the offset too.
	tag = (mdrTag_t *) lod;
	mdr->ofsTags = (int)((byte *) tag - (byte *) mdr);
	curtag = (mdrTag_t *) ((byte *)pinmodel + LittleLong(pinmodel->ofsTags));
	
	for (i = 0 ; i < mdr->numTags ; i++)
	{
		tag->boneIndex = LittleLong(curtag->boneIndex);
		strlcpy(tag->name, curtag->name, sizeof(tag->name));
		
		tag++;
		curtag++;
	}
	
	// And finally we know the offset to the end.
	mdr->ofsEnd = (int)((byte *) tag - (byte *) mdr);

	// phew! we're done.
	
	return qtrue;
}
/*
** GLW_LoadOpenGL
**
** GLimp_win.c internal function that attempts to load and use 
** a specific OpenGL DLL.
*/
static qboolean GLW_LoadOpenGL( const char *drivername )
{
	char buffer[1024];
	qboolean cdsFullscreen;

	Q_strncpyz( buffer, drivername, sizeof(buffer) );
	Q_strlwr(buffer);

	//
	// determine if we're on a standalone driver
	//
	if ( strstr( buffer, "opengl32" ) != 0 || r_maskMinidriver->integer )
	{
		glConfig.driverType = GLDRV_ICD;
	}
	else
	{
		glConfig.driverType = GLDRV_STANDALONE;

		ri.Printf( PRINT_ALL, "...assuming '%s' is a standalone driver\n", drivername );

		if ( strstr( buffer, _3DFX_DRIVER_NAME ) )
		{
			glConfig.driverType = GLDRV_VOODOO;
		}
	}

	// disable the 3Dfx splash screen
	_putenv("FX_GLIDE_NO_SPLASH=0");

	//
	// load the driver and bind our function pointers to it
	// 
	if ( QGL_Init( buffer ) ) 
	{
		cdsFullscreen = r_fullscreen->integer;

		// create the window and set up the context
		if ( !GLW_StartDriverAndSetMode( drivername, r_mode->integer, r_colorbits->integer, cdsFullscreen ) )
		{
			// if we're on a 24/32-bit desktop and we're going fullscreen on an ICD,
			// try it again but with a 16-bit desktop
			if ( glConfig.driverType == GLDRV_ICD )
			{
				if ( r_colorbits->integer != 16 ||
					 cdsFullscreen != qtrue ||
					 r_mode->integer != 3 )
				{
					if ( !GLW_StartDriverAndSetMode( drivername, 3, 16, qtrue ) )
					{
						goto fail;
					}
				}
			}
			else
			{
				goto fail;
			}
		}

		if ( glConfig.driverType == GLDRV_VOODOO )
		{
			glConfig.isFullscreen = qtrue;
		}

		return qtrue;
	}
fail:

	QGL_Shutdown();

	return qfalse;
}
Beispiel #27
0
/*
==============
G_Script_ScriptParse

  Parses the script for the given entity
==============
*/
void G_Script_ScriptParse(gentity_t *ent) {
	char                    *pScript;
	qboolean                wantName;
	qboolean                inScript;
	int                     eventNum;
	g_script_event_t        events[G_MAX_SCRIPT_STACK_ITEMS];
	int                     numEventItems;
	g_script_event_t        *curEvent;
	char                    params[MAX_INFO_STRING];
	g_script_stack_action_t *action;
	int                     i;
	int                     bracketLevel;
	qboolean                buildScript;

	if (!ent->scriptName) {
		return;
	}
	if (!level.scriptEntity) {
		return;
	}

	buildScript = trap_Cvar_VariableIntegerValue("com_buildScript");

	pScript  = level.scriptEntity;
	wantName = qtrue;
	inScript = qfalse;
	COM_BeginParseSession("G_Script_ScriptParse");
	bracketLevel  = 0;
	numEventItems = 0;

	memset(events, 0, sizeof (events));

	for (;;) {
		char *token;

		token = COM_Parse(&pScript);

		if (!token[0]) {
			if (!wantName) {
				G_Error("G_Script_ScriptParse(), Error (line %d): '}' expected, end of script found.\n", COM_GetCurrentParseLine());
			}
			break;
		}

		// end of script
		if (token[0] == '}') {
			if (inScript) {
				break;
			}
			if (wantName) {
				G_Error("G_Script_ScriptParse(), Error (line %d): '}' found, but not expected.\n", COM_GetCurrentParseLine());
			}
			wantName = qtrue;
		} else if (token[0] == '{') {
			if (wantName) {
				G_Error("G_Script_ScriptParse(), Error (line %d): '{' found, NAME expected.\n", COM_GetCurrentParseLine());
			}
		} else if (wantName) {
			if (!Q_stricmp(token, "bot")) {
				// a bot, skip this whole entry
				SkipRestOfLine(&pScript);
				// skip this section
				SkipBracedSection(&pScript);
				//
				continue;
			}
			if (!Q_stricmp(token, "entity")) {
				// this is an entity, so go back to look for a name
				continue;
			}
			if (!Q_stricmp(ent->scriptName, token)) {
				inScript      = qtrue;
				numEventItems = 0;
			}
			wantName = qfalse;
		} else if (inScript) {
			Q_strlwr(token);
			eventNum = G_Script_EventForString(token);
			if (eventNum < 0) {
				G_Error("G_Script_ScriptParse(), Error (line %d): unknown event: %s.\n", COM_GetCurrentParseLine(), token);
			}

			if (numEventItems >= G_MAX_SCRIPT_STACK_ITEMS) {
				G_Error("G_Script_ScriptParse(), Error (line %d): G_MAX_SCRIPT_STACK_ITEMS reached (%d)\n", COM_GetCurrentParseLine(), G_MAX_SCRIPT_STACK_ITEMS);
			}

			curEvent           = &events[numEventItems];
			curEvent->eventNum = eventNum;
			memset(params, 0, sizeof (params));

			// parse any event params before the start of this event's actions
			while ((token = COM_Parse(&pScript)) != NULL && (token[0] != '{')) {
				if (!token[0]) {
					G_Error("G_Script_ScriptParse(), Error (line %d): '}' expected, end of script found.\n", COM_GetCurrentParseLine());
				}

				if (strlen(params)) {      // add a space between each param
					Q_strcat(params, sizeof (params), " ");
				}
				Q_strcat(params, sizeof (params), token);
			}

			if (strlen(params)) {        // copy the params into the event
				curEvent->params = G_Alloc(strlen(params) + 1);
				Q_strncpyz(curEvent->params, params, strlen(params) + 1);
			}

			// parse the actions for this event
			while ((token = COM_Parse(&pScript)) != NULL && (token[0] != '}')) {
				if (!token[0]) {
					G_Error("G_Script_ScriptParse(), Error (line %d): '}' expected, end of script found.\n", COM_GetCurrentParseLine());
				}

				action = G_Script_ActionForString(token);
				if (!action) {
					G_Error("G_Script_ScriptParse(), Error (line %d): unknown action: %s.\n", COM_GetCurrentParseLine(), token);
				}

				curEvent->stack.items[curEvent->stack.numItems].action = action;

				memset(params, 0, sizeof (params));

				// Ikkyo - Parse for {}'s if this is a set command
				// Nico, added "create" & "delete" condition
				if (!Q_stricmp(action->actionString, "set") ||
				    !Q_stricmp(action->actionString, "create") ||
				    !Q_stricmp(action->actionString, "delete")) {
					token = COM_Parse(&pScript);
					if (token[0] != '{') {
						COM_ParseError("'{' expected, found: %s.\n", token);
					}

					while ((token = COM_Parse(&pScript)) != NULL && (token[0] != '}')) {
						if (strlen(params)) {     // add a space between each param
							Q_strcat(params, sizeof (params), " ");
						}

						if (strrchr(token, ' ')) {    // need to wrap this param in quotes since it has more than one word
							Q_strcat(params, sizeof (params), "\"");
						}

						Q_strcat(params, sizeof (params), token);

						if (strrchr(token, ' ')) {    // need to wrap this param in quotes since it has mor
							Q_strcat(params, sizeof (params), "\"");
						}
					}
				} else
				// hackly precaching of custom characters
				if (!Q_stricmp(token, "spawnbot")) {
					// this is fairly indepth, so I'll move it to a separate function for readability
					G_Script_ParseSpawnbot(&pScript, params, MAX_INFO_STRING);
				} else {
					token = COM_ParseExt(&pScript, qfalse);
					for (i = 0; token[0]; ++i) {
						if (strlen(params)) {     // add a space between each param
							Q_strcat(params, sizeof (params), " ");
						}

						if (i == 0) {
							// Special case: playsound's need to be cached on startup to prevent in-game pauses
							if (!Q_stricmp(action->actionString, "playsound")) {
								G_SoundIndex(token);
							} else if (!Q_stricmp(action->actionString, "changemodel")) {
								G_ModelIndex(token);
							} else if (buildScript &&
							           (!Q_stricmp(action->actionString, "mu_start") ||
							            !Q_stricmp(action->actionString, "mu_play") ||
							            !Q_stricmp(action->actionString, "mu_queue") ||
							            !Q_stricmp(action->actionString, "startcam")) &&
							           strlen(token)) {
								trap_SendServerCommand(-1, va("addToBuild %s\n", token));
							}
						}

						if ((i == 0 || i == 1) && !Q_stricmp(action->actionString, "remapshader")) {
							G_ShaderIndex(token);
						}

						if (strrchr(token, ' ')) {    // need to wrap this param in quotes since it has more than one word
							Q_strcat(params, sizeof (params), "\"");
						}

						Q_strcat(params, sizeof (params), token);

						if (strrchr(token, ' ')) {    // need to wrap this param in quotes since it has more than one word
							Q_strcat(params, sizeof (params), "\"");
						}

						token = COM_ParseExt(&pScript, qfalse);
					}
				}

				if (strlen(params)) {     // copy the params into the event
					curEvent->stack.items[curEvent->stack.numItems].params = G_Alloc(strlen(params) + 1);
					Q_strncpyz(curEvent->stack.items[curEvent->stack.numItems].params, params, strlen(params) + 1);
				}

				curEvent->stack.numItems++;

				if (curEvent->stack.numItems >= G_MAX_SCRIPT_STACK_ITEMS) {
					G_Error("G_Script_ScriptParse(): script exceeded G_MAX_SCRIPT_STACK_ITEMS (%d), line %d\n", G_MAX_SCRIPT_STACK_ITEMS, COM_GetCurrentParseLine());
				}
			}

			numEventItems++;
		} else {   // skip this character completely
			// TTimo gcc: suggest parentheses around assignment used as truth value
			while ((token = COM_Parse(&pScript)) != NULL) {
				if (!token[0]) {
					G_Error("G_Script_ScriptParse(), Error (line %d): '}' expected, end of script found.\n", COM_GetCurrentParseLine());
				} else if (token[0] == '{') {
					bracketLevel++;
				} else if (token[0] == '}' && !--bracketLevel) {
					break;
				}
			}
		}
	}

	// alloc and copy the events into the gentity_t for this cast
	if (numEventItems > 0) {
		ent->scriptEvents = G_Alloc(sizeof (g_script_event_t) * numEventItems);
		memcpy(ent->scriptEvents, events, sizeof (g_script_event_t) * numEventItems);
		ent->numScriptEvents = numEventItems;
	}
}
Beispiel #28
0
/*
 * Returns file size or -1 if not found. Can open separate files as well as
 * files inside pack files (both PAK and PK3).
 */
int
FS_FOpenFileRead(fsHandle_t *handle)
{
	char path[MAX_OSPATH];
	int i;
	fsSearchPath_t *search;
	fsPack_t *pack;

	file_from_pak = 0;
#ifdef ZIP
	file_from_pk3 = 0;
#endif

	/* Search through the path, one element at a time. */
	for (search = fs_searchPaths; search; search = search->next)
	{
		/* Search inside a pack file. */
		if (search->pack)
		{
			pack = search->pack;

			for (i = 0; i < pack->numFiles; i++)
			{
				if (Q_stricmp(pack->files[i].name, handle->name) == 0)
				{
					/* Found it! */
					Com_FilePath(pack->name, fs_fileInPath,
							sizeof(fs_fileInPath));
					fs_fileInPack = true;

					if (fs_debug->value)
					{
						Com_Printf("FS_FOpenFileRead: '%s' (found in '%s').\n",
								handle->name, pack->name);
					}

					if (pack->pak)
					{
						/* PAK */
						file_from_pak = 1;
						handle->file = fopen(pack->name, "rb");

						if (handle->file)
						{
							fseek(handle->file, pack->files[i].offset, SEEK_SET);
							return pack->files[i].size;
						}
					}
#ifdef ZIP
					else if (pack->pk3)
					{
						/* PK3 */
						file_from_pk3 = 1;
						Q_strlcpy(file_from_pk3_name, strrchr(pack->name,
										'/') + 1, sizeof(file_from_pk3_name));
						handle->zip = unzOpen(pack->name);

						if (handle->zip)
						{
							if (unzLocateFile(handle->zip, handle->name,
										2) == UNZ_OK)
							{
								if (unzOpenCurrentFile(handle->zip) == UNZ_OK)
								{
									return pack->files[i].size;
								}
							}

							unzClose(handle->zip);
						}
					}
#endif

					Com_Error(ERR_FATAL, "Couldn't reopen '%s'", pack->name);
				}
			}
		}
		else
		{
			/* Search in a directory tree. */
			Com_sprintf(path, sizeof(path), "%s/%s", search->path, handle->name);

			handle->file = fopen(path, "rb");

			if (!handle->file)
			{
				Q_strlwr(path);
				handle->file = fopen(path, "rb");
			}

			if (!handle->file)
			{
				continue;
			}

			if (handle->file)
			{
				/* Found it! */
				Q_strlcpy(fs_fileInPath, search->path, sizeof(fs_fileInPath));
				fs_fileInPack = false;

				if (fs_debug->value)
				{
					Com_Printf("FS_FOpenFileRead: '%s' (found in '%s').\n",
							handle->name, search->path);
				}

				return FS_FileLength(handle->file);
			}
		}
	}

	/* Not found! */
	fs_fileInPath[0] = 0;
	fs_fileInPack = false;

	if (fs_debug->value)
	{
		Com_Printf("FS_FOpenFileRead: couldn't find '%s'.\n", handle->name);
	}

	return -1;
}
DWORD EGLExceptionHandler (DWORD exceptionCode, LPEXCEPTION_POINTERS exceptionInfo)
{
	context = *exceptionInfo->ContextRecord;

	// Show the mouse cursor
	ShowCursor (TRUE);

	// Continue searching?
#ifdef _DEBUG
	if (MessageBoxA (NULL, "An unhandled exception occured in CleanCode!\n\nThis version was built with debug information. Do you have a debugger you can attach? If so, do this now, then click Yes, otherwise click No.", "Unhandled Exception", MB_ICONERROR|MB_YESNO) == IDYES)
		return EXCEPTION_CONTINUE_SEARCH;
#endif

	// Load needed libraries and get the location of the needed functions
	hDbgHelp = LoadLibraryA ("DBGHELP");
	if (!hDbgHelp)
	{
		MessageBoxA (NULL, APP_FULLNAME " has encountered an unhandled exception and must be terminated. No crash report could be generated since " APP_FULLNAME " failed to load DBGHELP.DLL. Please obtain DBGHELP.DLL and place it in your Quake II directory to enable crash dump generation.", "Unhandled Exception", MB_OK | MB_ICONEXCLAMATION);
		return EXCEPTION_CONTINUE_SEARCH;
	}

	hVersion = LoadLibraryA ("VERSION");
	if (hVersion)
	{
		fnVerQueryValue = (VERQUERYVALUE)GetProcAddress (hVersion, "VerQueryValueA");
		fnGetFileVersionInfo = (GETFILEVERSIONINFO)GetProcAddress (hVersion, "GetFileVersionInfoA");
		fnGetFileVersionInfoSize = (GETFILEVERSIONINFOSIZE)GetProcAddress (hVersion, "GetFileVersionInfoSizeA");
	}

	fnEnumerateLoadedModules64 = (ENUMERATELOADEDMODULES64)GetProcAddress (hDbgHelp, "EnumerateLoadedModules64");
	fnSymSetOptions = (SYMSETOPTIONS)GetProcAddress (hDbgHelp, "SymSetOptions");
	fnSymInitialize = (SYMINITIALIZE)GetProcAddress (hDbgHelp, "SymInitialize");
	fnSymFunctionTableAccess64 = (SYMFUNCTIONTABLEACCESS64)GetProcAddress (hDbgHelp, "SymFunctionTableAccess64");
	fnSymGetModuleBase64 = (SYMGETMODULEBASE64)GetProcAddress (hDbgHelp, "SymGetModuleBase64");
	fnStackWalk64 = (STACKWALK64)GetProcAddress (hDbgHelp, "StackWalk64");
	fnSymFromAddr = (SYMFROMADDR)GetProcAddress (hDbgHelp, "SymFromAddr");
	fnSymCleanup = (SYMCLEANUP)GetProcAddress (hDbgHelp, "SymCleanup");
	fnSymGetModuleInfo64 = (SYMGETMODULEINFO64)GetProcAddress (hDbgHelp, "SymGetModuleInfo64");
	//fnSymLoadModule64 = (SYMLOADMODULE64)GetProcAddress (hDbgHelp, "SymLoadModule64");
	fnMiniDumpWriteDump = (MINIDUMPWRITEDUMP)GetProcAddress (hDbgHelp, "MiniDumpWriteDump");

	if (!fnEnumerateLoadedModules64 || !fnSymSetOptions || !fnSymInitialize || !fnSymFunctionTableAccess64
	|| !fnSymGetModuleBase64 || !fnStackWalk64 || !fnSymFromAddr || !fnSymCleanup || !fnSymGetModuleInfo64)
	// || !fnSymLoadModule64)
	{
		FreeLibrary (hDbgHelp);
		if (hVersion)
			FreeLibrary (hVersion);
		MessageBoxA (NULL, APP_FULLNAME " has encountered an unhandled exception and must be terminated. No crash report could be generated since " APP_FULLNAME " failed to load DBGHELP.DLL. Please obtain DBGHELP.DLL and place it in your Quake II directory to enable crash dump generation.", "Unhandled Exception", MB_OK | MB_ICONEXCLAMATION);
		return EXCEPTION_CONTINUE_SEARCH;
	}

	// Let the user know
	if (MessageBoxA (NULL, APP_FULLNAME " has encountered an unhandled exception and must be terminated. Would you like to generate a crash report?", "Unhandled Exception", MB_ICONEXCLAMATION | MB_YESNO) == IDNO)
	{
		FreeLibrary (hDbgHelp);
		if (hVersion)
			FreeLibrary (hVersion);
		return EXCEPTION_CONTINUE_SEARCH;
	}

	// Get the current process
	hProcess = GetCurrentProcess();

	fnSymSetOptions (SYMOPT_UNDNAME | SYMOPT_FAIL_CRITICAL_ERRORS | SYMOPT_LOAD_ANYTHING);

	// Used to determine the directory for dump placement
	GetModuleFileNameA (NULL, searchPath, sizeof(searchPath));
	tempPointer = strrchr (searchPath, '\\');
	if (tempPointer)
		*tempPointer = '\0';

	// Get the system time
	GetSystemTime (&timeInfo);

	// Find the next filename to use for this dump
	sint32 dumpNum = 1;
	for (; ; dumpNum++)
	{
		Q_snprintfz (reportPath, sizeof(reportPath), "%s\\CCCrashLog%.4d-%.2d-%.2d_%d.txt", searchPath, timeInfo.wYear, timeInfo.wMonth, timeInfo.wDay, dumpNum);
		if (Sys_FileLength (reportPath) == -1)
			break;
	}

	// Open the report dump file
	fhReport = fopen (reportPath, "wb");

	if (!fhReport)
	{
		FreeLibrary (hDbgHelp);
		if (hVersion)
			FreeLibrary (hVersion);
		return EXCEPTION_CONTINUE_SEARCH;
	}

	// Initialize symbols
	fnSymInitialize (hProcess, searchPath, TRUE);
#ifdef _M_AMD64
	InstructionPtr = context.Rip;
	frame.AddrPC.Offset = InstructionPtr;
	frame.AddrFrame.Offset = context.Rbp;
	frame.AddrPC.Offset = context.Rsp;
#else
	InstructionPtr = context.Eip;
	frame.AddrPC.Offset = InstructionPtr;
	frame.AddrFrame.Offset = context.Ebp;
	frame.AddrStack.Offset = context.Esp;
#endif

	frame.AddrFrame.Mode = AddrModeFlat;
	frame.AddrPC.Mode = AddrModeFlat;
	frame.AddrStack.Mode = AddrModeFlat;

	symInfo = (SYMBOL_INFO*)LocalAlloc (LPTR, sizeof(*symInfo) + 128);
	symInfo->SizeOfStruct = sizeof(SYMBOL_INFO);
	symInfo->MaxNameLen = 128;
	fnOffset = 0;

	// Get OS info
	Mem_Zero (&osInfo, sizeof(osInfo));
	osInfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);
	if (!GetVersionEx ((OSVERSIONINFO *)&osInfo))
	{
		osInfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
		GetVersionEx ((OSVERSIONINFO *)&osInfo);
	}

	// Find out which module threw the exception
	Q_strncpyz (szModuleName, "<unknown>", sizeof(szModuleName));
	fnEnumerateLoadedModules64 (hProcess, (PENUMLOADED_MODULES_CALLBACK64)EnumerateLoadedModulesProcInfo, (VOID *)InstructionPtr);
	Q_strlwr (szModuleName);

	if (strstr (szModuleName, "gamex86"))
	{
		upMessage =
			"CleanCode's Gamex86 seems to be the root problem.\r\n"
			"If this is not base CleanCode, send the report to the mod author,\r\n"
			"otherwise send it to Paril (see the log .txt for more info)\r\n";
#ifdef USE_CURL
		upload = false;
#endif
	}
	else
	{
		upMessage =
			"Unable to detect where the exception occured!\r\n";
#ifdef USE_CURL
		upload = true;
#endif
	}

	// Write out the report to file
	fprintf (fhReport,
		APP_FULLNAME " encountered an unhandled exception and was terminated. If you are\r\n"
		"able to reproduce this crash, please submit the crash report when prompted, or email\r\n"
		"the file to Paril or any CleanCode project member. Goto http://code.google.com/p/cleancodequake2 and click on\r\n"
		"Issues, and file a bug report, or email [email protected] with the report.\r\n"
		"\r\n"
		"*** PLEASE MAKE SURE THAT YOU ARE USING THE LATEST VERSION OF CLEANCODE BEFORE SUBMITTING ***\r\nYour Cleancode Version: "CLEANCODE_VERSION_PRINT"\r\n", CLEANCODE_VERSION_PRINT_ARGS);

	fprintf (fhReport, "\r\n");

	// Windows information
	fprintf (fhReport, "Windows information:\r\n");
	fprintf (fhReport, "--------------------------------------------------\r\n");
	fprintf (fhReport, "String:       %s\r\n", GetOSDisplayString().CString());
	fprintf (fhReport, "Version:      %d.%d\r\n", osInfo.dwMajorVersion, osInfo.dwMinorVersion);
	fprintf (fhReport, "Build:        %d\r\n", osInfo.dwBuildNumber);
	fprintf (fhReport, "Service Pack: %s\r\n", osInfo.szCSDVersion[0] ? osInfo.szCSDVersion : "none");

	fprintf (fhReport, "\r\n");

	// Exception information
	fprintf (fhReport, "Exception information:\r\n");
	fprintf (fhReport, "--------------------------------------------------\r\n");
	fprintf (fhReport, "Code:    "HEX_VALUE_32"\r\n", exceptionCode);
	fprintf (fhReport, "Address: "HEX_VALUE_64"\r\n", InstructionPtr);
	fprintf (fhReport, "Module:  %s\r\n", szModuleName);

	fprintf (fhReport, "\r\n");

	// Symbol information
	fprintf (fhReport, "Symbol information:\r\n");
	fprintf (fhReport, "Name                                                        Symbol Type\r\n");
	fprintf (fhReport, "-----------------------------------------------------------------------\r\n");
	fnEnumerateLoadedModules64 (hProcess, (PENUMLOADED_MODULES_CALLBACK64)EEnumerateLoadedModulesProcSymInfoHeap::EnumerateLoadedModulesProcSymInfo, (VOID *)fhReport);

	fprintf (fhReport, "\r\n");

	// Loaded modules
	fprintf (fhReport, "Loaded modules:\r\n");
	fprintf (fhReport, "--------------------------------------------------\r\n");
	fnEnumerateLoadedModules64 (hProcess, (PENUMLOADED_MODULES_CALLBACK64)EnumerateLoadedModulesProcDump, (VOID *)fhReport);

	fprintf (fhReport, "\r\n");

	// Stack trace
	fprintf (fhReport, "Stack trace:\r\n");
	fprintf (fhReport, "--------------------------------------------------\r\n");
	fprintf (fhReport, "Stack      EIP        Arg0       Arg1       Arg2       Arg3       Address\r\n");
	while (fnStackWalk64 (IMAGE_FILE_MACHINE_I386, hProcess, GetCurrentThread(), &frame, &context, NULL, (PFUNCTION_TABLE_ACCESS_ROUTINE64)fnSymFunctionTableAccess64, (PGET_MODULE_BASE_ROUTINE64)fnSymGetModuleBase64, NULL))
	{
		Q_strncpyz (szModuleName, "<unknown>", sizeof(szModuleName));
		fnEnumerateLoadedModules64 (hProcess, (PENUMLOADED_MODULES_CALLBACK64)EnumerateLoadedModulesProcInfo, (VOID *)(DWORD)frame.AddrPC.Offset);

		tempPointer = strrchr (szModuleName, '\\');
		if (tempPointer)
			tempPointer++;
		else
			tempPointer = szModuleName;

		fprintf (fhReport, ""HEX_VALUE_64" "HEX_VALUE_64" "HEX_VALUE_32" "HEX_VALUE_32" "HEX_VALUE_32" "HEX_VALUE_32" %-20s ! ",
			frame.AddrStack.Offset, frame.AddrPC.Offset, (DWORD)frame.Params[0], (DWORD)frame.Params[1], (DWORD)frame.Params[2], (DWORD)frame.Params[3], tempPointer);

		if (fnSymFromAddr (hProcess, frame.AddrPC.Offset, &fnOffset, symInfo) && !(symInfo->Flags & SYMFLAG_EXPORT))
			fprintf (fhReport, "%-24s + "HEX_VALUE_64" %lu\r\n", symInfo->Name, fnOffset, symInfo->Tag);
		else
			fprintf (fhReport, ""HEX_VALUE_64"\r\n", frame.AddrPC.Offset);
	}

	fprintf (fhReport, "\r\n");

	// Write a minidump
	if (fnMiniDumpWriteDump)
	{
		HANDLE	hFile;

		//GetTempPath (sizeof(dumpPath)-16, dumpPath);
		Q_snprintfz (dumpPath, sizeof(dumpPath), "%s\\CCCrashLog%.4d-%.2d-%.2d_%d.dmp", searchPath, timeInfo.wYear, timeInfo.wMonth, timeInfo.wDay, dumpNum);

		hFile = CreateFileA (dumpPath, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
		if (hFile != INVALID_HANDLE_VALUE)
		{
			miniInfo.ClientPointers = TRUE;
			miniInfo.ExceptionPointers = exceptionInfo;
			miniInfo.ThreadId = GetCurrentThreadId ();
			if (fnMiniDumpWriteDump (hProcess, GetCurrentProcessId(), hFile, (MINIDUMP_TYPE)(MiniDumpWithIndirectlyReferencedMemory|MiniDumpWithDataSegs), &miniInfo, NULL, NULL))
			{
				CloseHandle (hFile);

				FILE	*fh;
#ifdef USE_GZ
				CHAR	zPath[MAX_PATH];
#endif

				fh = fopen (dumpPath, "rb");
				if (fh)
#ifdef USE_GZ
				{
					gzFile	gz;

					Q_snprintfz (zPath, sizeof(zPath)-1, "%s\\CCCrashLog%.4d-%.2d-%.2d_%d.dmp.gz", searchPath, timeInfo.wYear, timeInfo.wMonth, timeInfo.wDay, dumpNum);
					gz = gzopen (zPath, "wb");
					if (gz)
					{
						size_t len;
						while ((len = fread (gzBuff, 1, sizeof(gzBuff), fh)) > 0)
							gzwrite (gz, gzBuff, (uint32)len);
						gzclose (gz);
#endif
						fclose (fh);
#ifdef USE_GZ
					}
				}
#endif
		
#ifdef USE_GZ
				DeleteFileA (dumpPath);
				Q_strncpyz (dumpPath, zPath, sizeof(dumpPath));
#endif

				fprintf (fhReport, "A "
#ifdef USE_GZ
					"minidump"
#else
					"dump"
#endif
					" was saved to %s.\r\nPlease include this file when posting a crash report.\r\n", dumpPath);
			}
			else
			{
				CloseHandle (hFile);
				DeleteFileA (dumpPath);
			}
		}
	}
	else
		fprintf (fhReport, "A minidump could not be created. Minidumps are only available on Windows XP or later.\r\n");

	// Done writing reports
	fclose (fhReport);
	LocalFree (symInfo);
	fnSymCleanup (hProcess);

	// Let the client know
	String temp = String::Format("Report written to: %s\r\nMini-dump written to %s\r\nPlease include both files if you submit manually!\r\n", reportPath, dumpPath);
	MessageBoxA (NULL, temp.CString(), "Unhandled Exception", MB_ICONEXCLAMATION | MB_OK);

#ifdef USE_CURL
	if (upload)
	{
		ret = MessageBox (NULL, "Would you like to automatically upload this crash report for analysis?\nPlease do not submit multiple reports of the same crash as this will only delay processing.", "Unhandled Exception", MB_ICONQUESTION | MB_YESNO | MB_DEFBUTTON2);
		if (ret == IDYES)
			EGLUploadCrashDump (dumpPath, reportPath);
		else
			MessageBox (NULL, "You have chosen to manually upload the crash report.\nPlease include BOTH the crash log and mini-dump when you post it on the EGL forums!\n", "Submit manually", MB_ICONEXCLAMATION|MB_OK);
	}
	else
#endif
	MessageBoxA (NULL, upMessage, "Unhandled Exception", MB_OK|MB_ICONEXCLAMATION);

	// Done
	FreeLibrary (hDbgHelp);
	if (hVersion)
		FreeLibrary (hVersion);

	return EXCEPTION_EXECUTE_HANDLER;
}
/*
=================
R_LoadMD3
=================
*/
static qboolean R_LoadMD3 (model_t *mod, int lod, void *buffer, const char *mod_name, qboolean bAlreadyCached ) {
	int					i, j;
	md3Header_t			*pinmodel;
	md3Surface_t		*surf;
	md3Shader_t			*shader;
	int					version;
	int					size;

#ifndef _M_IX86
	md3Frame_t			*frame;
	md3Triangle_t		*tri;
	md3St_t				*st;
	md3XyzNormal_t		*xyz;
	md3Tag_t			*tag;
#endif


	pinmodel= (md3Header_t *)buffer;
	//
	// read some fields from the binary, but only LittleLong() them when we know this wasn't an already-cached model...
	//
	version = pinmodel->version;
	size	= pinmodel->ofsEnd;

	if (!bAlreadyCached)
	{
		version = LittleLong(version);
		size	= LittleLong(size);
	}
	
	if (version != MD3_VERSION) {
		ri.Printf( PRINT_WARNING, "R_LoadMD3: %s has wrong version (%i should be %i)\n",
				 mod_name, version, MD3_VERSION);
		return qfalse;
	}

	mod->type      = MOD_MESH;	
	mod->dataSize += size;

	qboolean bAlreadyFound = qfalse;
	mod->md3[lod] = (md3Header_t *) //ri.Hunk_Alloc( size );
										RE_RegisterModels_Malloc(size, mod_name, &bAlreadyFound, TAG_MODEL_MD3);

	assert(bAlreadyCached == bAlreadyFound);	// I should probably eliminate 'bAlreadyFound', but wtf?

	if (!bAlreadyFound)
	{	
		memcpy (mod->md3[lod], buffer, size );

		LL(mod->md3[lod]->ident);
		LL(mod->md3[lod]->version);
		LL(mod->md3[lod]->numFrames);
		LL(mod->md3[lod]->numTags);
		LL(mod->md3[lod]->numSurfaces);
		LL(mod->md3[lod]->ofsFrames);
		LL(mod->md3[lod]->ofsTags);
		LL(mod->md3[lod]->ofsSurfaces);
		LL(mod->md3[lod]->ofsEnd);
	}

	if ( mod->md3[lod]->numFrames < 1 ) {
		ri.Printf( PRINT_WARNING, "R_LoadMD3: %s has no frames\n", mod_name );
		return qfalse;
	}

	if (bAlreadyFound)
	{
		return qtrue;	// All done. Stop, go no further, do not pass Go...
	}

#ifndef _M_IX86
	//
	// optimisation, we don't bother doing this for standard intel case since our data's already in that format...
	//

	// swap all the frames
    frame = (md3Frame_t *) ( (byte *)mod->md3[lod] + mod->md3[lod]->ofsFrames );
    for ( i = 0 ; i < mod->md3[lod]->numFrames ; i++, frame++) {
    	frame->radius = LittleFloat( frame->radius );
        for ( j = 0 ; j < 3 ; j++ ) {
            frame->bounds[0][j] = LittleFloat( frame->bounds[0][j] );
            frame->bounds[1][j] = LittleFloat( frame->bounds[1][j] );
	    	frame->localOrigin[j] = LittleFloat( frame->localOrigin[j] );
        }
	}

	// swap all the tags
    tag = (md3Tag_t *) ( (byte *)mod->md3[lod] + mod->md3[lod]->ofsTags );
    for ( i = 0 ; i < mod->md3[lod]->numTags * mod->md3[lod]->numFrames ; i++, tag++) {
        for ( j = 0 ; j < 3 ; j++ ) {
			tag->origin[j] = LittleFloat( tag->origin[j] );
			tag->axis[0][j] = LittleFloat( tag->axis[0][j] );
			tag->axis[1][j] = LittleFloat( tag->axis[1][j] );
			tag->axis[2][j] = LittleFloat( tag->axis[2][j] );
        }
	}
#endif

	// swap all the surfaces
	surf = (md3Surface_t *) ( (byte *)mod->md3[lod] + mod->md3[lod]->ofsSurfaces );
	for ( i = 0 ; i < mod->md3[lod]->numSurfaces ; i++) {
        LL(surf->flags);
        LL(surf->numFrames);
        LL(surf->numShaders);
        LL(surf->numTriangles);
        LL(surf->ofsTriangles);
        LL(surf->numVerts);
        LL(surf->ofsShaders);
        LL(surf->ofsSt);
        LL(surf->ofsXyzNormals);
        LL(surf->ofsEnd);
		
		if ( surf->numVerts > SHADER_MAX_VERTEXES ) {
			ri.Error (ERR_DROP, "R_LoadMD3: %s has more than %i verts on a surface (%i)",
				mod_name, SHADER_MAX_VERTEXES, surf->numVerts );
		}
		if ( surf->numTriangles*3 > SHADER_MAX_INDEXES ) {
			ri.Error (ERR_DROP, "R_LoadMD3: %s has more than %i triangles on a surface (%i)",
				mod_name, SHADER_MAX_INDEXES / 3, surf->numTriangles );
		}
	
		// change to surface identifier
		surf->ident = SF_MD3;

		// lowercase the surface name so skin compares are faster
		Q_strlwr( surf->name );

		// strip off a trailing _1 or _2
		// this is a crutch for q3data being a mess
		j = strlen( surf->name );
		if ( j > 2 && surf->name[j-2] == '_' ) {
			surf->name[j-2] = 0;
		}

        // register the shaders
        shader = (md3Shader_t *) ( (byte *)surf + surf->ofsShaders );
        for ( j = 0 ; j < surf->numShaders ; j++, shader++ ) {
            shader_t	*sh;

            sh = R_FindShader( shader->name, lightmapsNone, stylesDefault, qtrue );
			if ( sh->defaultShader ) {
				shader->shaderIndex = 0;
			} else {
				shader->shaderIndex = sh->index;
			}
			RE_RegisterModels_StoreShaderRequest(mod_name, &shader->name[0], &shader->shaderIndex);
        }


#ifndef _M_IX86
//
// optimisation, we don't bother doing this for standard intel case since our data's already in that format...
//

		// swap all the triangles
		tri = (md3Triangle_t *) ( (byte *)surf + surf->ofsTriangles );
		for ( j = 0 ; j < surf->numTriangles ; j++, tri++ ) {
			LL(tri->indexes[0]);
			LL(tri->indexes[1]);
			LL(tri->indexes[2]);
		}

		// swap all the ST
        st = (md3St_t *) ( (byte *)surf + surf->ofsSt );
        for ( j = 0 ; j < surf->numVerts ; j++, st++ ) {
            st->st[0] = LittleFloat( st->st[0] );
            st->st[1] = LittleFloat( st->st[1] );
        }

		// swap all the XyzNormals
        xyz = (md3XyzNormal_t *) ( (byte *)surf + surf->ofsXyzNormals );
        for ( j = 0 ; j < surf->numVerts * surf->numFrames ; j++, xyz++ ) 
		{
            xyz->xyz[0] = LittleShort( xyz->xyz[0] );
            xyz->xyz[1] = LittleShort( xyz->xyz[1] );
            xyz->xyz[2] = LittleShort( xyz->xyz[2] );

            xyz->normal = LittleShort( xyz->normal );
        }
#endif

		// find the next surface
		surf = (md3Surface_t *)( (byte *)surf + surf->ofsEnd );
	}
    
	return qtrue;
}