/* * 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 ); }
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(); }
/* =============== 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); } }
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; }
/* ================= 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; }
/* ================= 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; }
// 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; }
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++; }
// 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); }
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); }
/* ================= 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; }
/* =================== 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 ); }
/* ================= 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; }
/* ================== 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 " ) ) { } }
/* =============== 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; }
// 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; }
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; }
/* ================= 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; }
/* ** 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(); }
/* ==================== 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; }
/* * 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 ) ); }
/* ================= 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; }
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; }
/* ============== 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; } }
/* * 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; }