/* ================== CL_ParseGamestate ================== */ void CL_ParseGamestate( msg_t *msg ) { int i; entityState_t *es; int newnum; entityState_t nullstate; int cmd; char *s; Con_Close(); clc.connectPacketCount = 0; // wipe local client state CL_ClearState(); #ifdef _DONETPROFILE_ int startBytes,endBytes; startBytes=msg->readcount; #endif // a gamestate always marks a server command sequence clc.serverCommandSequence = MSG_ReadLong( msg ); // parse all the configstrings and baselines cl.gameState.dataCount = 1; // leave a 0 at the beginning for uninitialized configstrings while ( 1 ) { cmd = MSG_ReadByte( msg ); if ( cmd == svc_EOF ) { break; } if ( cmd == svc_configstring ) { int len, start; start = msg->readcount; i = MSG_ReadShort( msg ); if ( i < 0 || i >= MAX_CONFIGSTRINGS ) { Com_Error( ERR_DROP, "configstring > MAX_CONFIGSTRINGS" ); } s = MSG_ReadBigString( msg ); if (cl_shownet->integer >= 2) { Com_Printf("%3i: %d: %s\n", start, i, s); } /* if (i == CS_SERVERINFO) { //get the special value here char *f = strstr(s, "g_debugMelee"); if (f) { while (*f && *f != '\\') { //find the \ after it f++; } if (*f == '\\') { //got it int i = 0; f++; while (*f && *f != '\\' && i < 128) { hiddenCvarVal[i] = *f; i++; f++; } hiddenCvarVal[i] = 0; //resume here s = f; } } } */ len = strlen( s ); if ( len + 1 + cl.gameState.dataCount > MAX_GAMESTATE_CHARS ) { Com_Error( ERR_DROP, "MAX_GAMESTATE_CHARS exceeded" ); } // append it to the gameState string buffer cl.gameState.stringOffsets[ i ] = cl.gameState.dataCount; Com_Memcpy( cl.gameState.stringData + cl.gameState.dataCount, s, len + 1 ); cl.gameState.dataCount += len + 1; } else if ( cmd == svc_baseline ) { newnum = MSG_ReadBits( msg, GENTITYNUM_BITS ); if ( newnum < 0 || newnum >= MAX_GENTITIES ) { Com_Error( ERR_DROP, "Baseline number out of range: %i", newnum ); } Com_Memset (&nullstate, 0, sizeof(nullstate)); es = &cl.entityBaselines[ newnum ]; MSG_ReadDeltaEntity( msg, &nullstate, es, newnum ); } else { Com_Error( ERR_DROP, "CL_ParseGamestate: bad command byte" ); } } clc.clientNum = MSG_ReadLong(msg); // read the checksum feed clc.checksumFeed = MSG_ReadLong( msg ); CL_ParseRMG ( msg ); //rwwRMG - get info for it from the server #ifdef _DONETPROFILE_ endBytes=msg->readcount; // ClReadProf().AddField("svc_gamestate",endBytes-startBytes); #endif // parse serverId and other cvars CL_SystemInfoChanged(); // reinitialize the filesystem if the game directory has changed if( FS_ConditionalRestart( clc.checksumFeed ) ) { // don't set to true because we yet have to start downloading // enabling this can cause double loading of a map when connecting to // a server which has a different game directory set //clc.downloadRestart = qtrue; } // This used to call CL_StartHunkUsers, but now we enter the download state before loading the // cgame CL_InitDownloads(); // make sure the game starts Cvar_Set( "cl_paused", "0" ); }
void AddWindingToConvexHull( winding_t *w, winding_t **hull, vec3_t normal ) { int i, j, k; float *p, *copy; vec3_t dir; float d; int numHullPoints, numNew; vec3_t hullPoints[MAX_HULL_POINTS]; vec3_t newHullPoints[MAX_HULL_POINTS]; vec3_t hullDirs[MAX_HULL_POINTS]; qboolean hullSide[MAX_HULL_POINTS]; qboolean outside; if ( !*hull ) { *hull = CopyWinding( w ); return; } numHullPoints = (*hull)->numpoints; Com_Memcpy( hullPoints, (*hull)->p, numHullPoints * sizeof(vec3_t) ); for ( i = 0 ; i < w->numpoints ; i++ ) { p = w->p[i]; // calculate hull side vectors for ( j = 0 ; j < numHullPoints ; j++ ) { k = ( j + 1 ) % numHullPoints; VectorSubtract( hullPoints[k], hullPoints[j], dir ); VectorNormalize2( dir, dir ); CrossProduct( normal, dir, hullDirs[j] ); } outside = qfalse; for ( j = 0 ; j < numHullPoints ; j++ ) { VectorSubtract( p, hullPoints[j], dir ); d = DotProduct( dir, hullDirs[j] ); if ( d >= ON_EPSILON ) { outside = qtrue; } if ( d >= -ON_EPSILON ) { hullSide[j] = qtrue; } else { hullSide[j] = qfalse; } } // if the point is effectively inside, do nothing if ( !outside ) { continue; } // find the back side to front side transition for ( j = 0 ; j < numHullPoints ; j++ ) { if ( !hullSide[ j % numHullPoints ] && hullSide[ (j + 1) % numHullPoints ] ) { break; } } if ( j == numHullPoints ) { continue; } // insert the point here VectorCopy( p, newHullPoints[0] ); numNew = 1; // copy over all points that aren't double fronts j = (j+1)%numHullPoints; for ( k = 0 ; k < numHullPoints ; k++ ) { if ( hullSide[ (j+k) % numHullPoints ] && hullSide[ (j+k+1) % numHullPoints ] ) { continue; } copy = hullPoints[ (j+k+1) % numHullPoints ]; VectorCopy( copy, newHullPoints[numNew] ); numNew++; } numHullPoints = numNew; Com_Memcpy( hullPoints, newHullPoints, numHullPoints * sizeof(vec3_t) ); } FreeWinding( *hull ); w = AllocWinding( numHullPoints ); w->numpoints = numHullPoints; *hull = w; Com_Memcpy( w->p, hullPoints, numHullPoints * sizeof(vec3_t) ); }
/* ===================== CL_ConfigstringModified ===================== */ void CL_ConfigstringModified(void) { char *old, *s; int i, index; char *dup; gameState_t oldGs; int len; index = atoi(Cmd_Argv(1)); if(index < 0 || index >= MAX_CONFIGSTRINGS) { Com_Error(ERR_DROP, "configstring > MAX_CONFIGSTRINGS"); } // get everything after "cs <num>" s = Cmd_ArgsFrom(2); old = cl.gameState.stringData + cl.gameState.stringOffsets[index]; if(!strcmp(old, s)) { return; // unchanged } // build the new gameState_t oldGs = cl.gameState; Com_Memset(&cl.gameState, 0, sizeof(cl.gameState)); // leave the first 0 for uninitialized strings cl.gameState.dataCount = 1; for(i = 0; i < MAX_CONFIGSTRINGS; i++) { if(i == index) { dup = s; } else { dup = oldGs.stringData + oldGs.stringOffsets[i]; } if(!dup[0]) { continue; // leave with the default empty string } len = strlen(dup); if(len + 1 + cl.gameState.dataCount > MAX_GAMESTATE_CHARS) { Com_Error(ERR_DROP, "MAX_GAMESTATE_CHARS exceeded"); } // append it to the gameState string buffer cl.gameState.stringOffsets[i] = cl.gameState.dataCount; Com_Memcpy(cl.gameState.stringData + cl.gameState.dataCount, dup, len + 1); cl.gameState.dataCount += len + 1; } if(index == CS_SYSTEMINFO) { // parse serverId and other cvars CL_SystemInfoChanged(); } }
/* ==================== CL_UISystemCalls The ui module is making a system call ==================== */ intptr_t CL_UISystemCalls( intptr_t *args ) { switch( args[0] ) { case UI_ERROR: Com_Error( ERR_DROP, "%s", (const char*)VMA(1) ); return 0; case UI_PRINT: Com_Printf( "%s", (const char*)VMA(1) ); return 0; case UI_MILLISECONDS: return Sys_Milliseconds(); case UI_CVAR_REGISTER: Cvar_Register( VMA(1), VMA(2), VMA(3), args[4] ); return 0; case UI_CVAR_UPDATE: Cvar_Update( VMA(1) ); return 0; case UI_CVAR_SET: Cvar_Set( VMA(1), VMA(2) ); return 0; case UI_CVAR_VARIABLEVALUE: return FloatAsInt( Cvar_VariableValue( VMA(1) ) ); case UI_CVAR_VARIABLESTRINGBUFFER: Cvar_VariableStringBuffer( VMA(1), VMA(2), args[3] ); return 0; case UI_CVAR_SETVALUE: Cvar_SetValue( VMA(1), VMF(2) ); return 0; case UI_CVAR_RESET: Cvar_Reset( VMA(1) ); return 0; case UI_CVAR_CREATE: Cvar_Get( VMA(1), VMA(2), args[3] ); return 0; case UI_CVAR_INFOSTRINGBUFFER: Cvar_InfoStringBuffer( args[1], VMA(2), args[3] ); return 0; case UI_ARGC: return Cmd_Argc(); case UI_ARGV: Cmd_ArgvBuffer( args[1], VMA(2), args[3] ); return 0; case UI_CMD_EXECUTETEXT: Cbuf_ExecuteText( args[1], VMA(2) ); return 0; case UI_FS_FOPENFILE: return FS_FOpenFileByMode( VMA(1), VMA(2), args[3] ); case UI_FS_READ: FS_Read2( VMA(1), args[2], args[3] ); return 0; case UI_FS_WRITE: FS_Write( VMA(1), args[2], args[3] ); return 0; case UI_FS_FCLOSEFILE: FS_FCloseFile( args[1] ); return 0; case UI_FS_GETFILELIST: return FS_GetFileList( VMA(1), VMA(2), VMA(3), args[4] ); case UI_FS_SEEK: return FS_Seek( args[1], args[2], args[3] ); case UI_R_REGISTERMODEL: return re.RegisterModel( VMA(1) ); case UI_R_REGISTERSKIN: return re.RegisterSkin( VMA(1) ); case UI_R_REGISTERSHADERNOMIP: return re.RegisterShaderNoMip( VMA(1) ); case UI_R_CLEARSCENE: re.ClearScene(); return 0; case UI_R_ADDREFENTITYTOSCENE: re.AddRefEntityToScene( VMA(1) ); return 0; case UI_R_ADDPOLYTOSCENE: re.AddPolyToScene( args[1], args[2], VMA(3), 1 ); return 0; case UI_R_ADDLIGHTTOSCENE: re.AddLightToScene( VMA(1), VMF(2), VMF(3), VMF(4), VMF(5) ); return 0; case UI_R_RENDERSCENE: re.RenderScene( VMA(1) ); return 0; case UI_R_SETCOLOR: re.SetColor( VMA(1) ); return 0; case UI_R_DRAWSTRETCHPIC: re.DrawStretchPic( VMF(1), VMF(2), VMF(3), VMF(4), VMF(5), VMF(6), VMF(7), VMF(8), args[9] ); return 0; case UI_R_MODELBOUNDS: re.ModelBounds( args[1], VMA(2), VMA(3) ); return 0; case UI_UPDATESCREEN: SCR_UpdateScreen(); return 0; case UI_CM_LERPTAG: re.LerpTag( VMA(1), args[2], args[3], args[4], VMF(5), VMA(6) ); return 0; case UI_S_REGISTERSOUND: return S_RegisterSound( VMA(1), args[2] ); case UI_S_STARTLOCALSOUND: S_StartLocalSound( args[1], args[2] ); return 0; case UI_KEY_KEYNUMTOSTRINGBUF: Key_KeynumToStringBuf( args[1], VMA(2), args[3] ); return 0; case UI_KEY_GETBINDINGBUF: Key_GetBindingBuf( args[1], VMA(2), args[3] ); return 0; case UI_KEY_SETBINDING: Key_SetBinding( args[1], VMA(2) ); return 0; case UI_KEY_ISDOWN: return Key_IsDown( args[1] ); case UI_KEY_GETOVERSTRIKEMODE: return Key_GetOverstrikeMode(); case UI_KEY_SETOVERSTRIKEMODE: Key_SetOverstrikeMode( args[1] ); return 0; case UI_KEY_CLEARSTATES: Key_ClearStates(); return 0; case UI_KEY_GETCATCHER: return Key_GetCatcher(); case UI_KEY_SETCATCHER: Key_SetCatcher( args[1] ); return 0; case UI_GETCLIPBOARDDATA: CL_GetClipboardData( VMA(1), args[2] ); return 0; case UI_GETCLIENTSTATE: GetClientState( VMA(1) ); return 0; case UI_GETGLCONFIG: CL_GetGlconfig( VMA(1) ); return 0; case UI_GETCONFIGSTRING: return GetConfigString( args[1], VMA(2), args[3] ); case UI_LAN_LOADCACHEDSERVERS: LAN_LoadCachedServers(); return 0; case UI_LAN_SAVECACHEDSERVERS: LAN_SaveServersToCache(); return 0; case UI_LAN_ADDSERVER: return LAN_AddServer(args[1], VMA(2), VMA(3)); case UI_LAN_REMOVESERVER: LAN_RemoveServer(args[1], VMA(2)); return 0; case UI_LAN_GETPINGQUEUECOUNT: return LAN_GetPingQueueCount(); case UI_LAN_CLEARPING: LAN_ClearPing( args[1] ); return 0; case UI_LAN_GETPING: LAN_GetPing( args[1], VMA(2), args[3], VMA(4) ); return 0; case UI_LAN_GETPINGINFO: LAN_GetPingInfo( args[1], VMA(2), args[3] ); return 0; case UI_LAN_GETSERVERCOUNT: return LAN_GetServerCount(args[1]); case UI_LAN_GETSERVERADDRESSSTRING: LAN_GetServerAddressString( args[1], args[2], VMA(3), args[4] ); return 0; case UI_LAN_GETSERVERINFO: LAN_GetServerInfo( args[1], args[2], VMA(3), args[4] ); return 0; case UI_LAN_GETSERVERPING: return LAN_GetServerPing( args[1], args[2] ); case UI_LAN_MARKSERVERVISIBLE: LAN_MarkServerVisible( args[1], args[2], args[3] ); return 0; case UI_LAN_SERVERISVISIBLE: return LAN_ServerIsVisible( args[1], args[2] ); case UI_LAN_UPDATEVISIBLEPINGS: return LAN_UpdateVisiblePings( args[1] ); case UI_LAN_RESETPINGS: LAN_ResetPings( args[1] ); return 0; case UI_LAN_SERVERSTATUS: return LAN_GetServerStatus( VMA(1), VMA(2), args[3] ); case UI_LAN_COMPARESERVERS: return LAN_CompareServers( args[1], args[2], args[3], args[4], args[5] ); case UI_MEMORY_REMAINING: return Hunk_MemoryRemaining(); case UI_GET_CDKEY: CLUI_GetCDKey( VMA(1), args[2] ); return 0; case UI_SET_CDKEY: CLUI_SetCDKey( VMA(1) ); return 0; case UI_SET_PBCLSTATUS: return 0; case UI_R_REGISTERFONT: re.RegisterFont( VMA(1), args[2], VMA(3)); return 0; case UI_MEMSET: Com_Memset( VMA(1), args[2], args[3] ); return 0; case UI_MEMCPY: Com_Memcpy( VMA(1), VMA(2), args[3] ); return 0; case UI_STRNCPY: strncpy( VMA(1), VMA(2), args[3] ); return args[1]; case UI_SIN: return FloatAsInt( sin( VMF(1) ) ); case UI_COS: return FloatAsInt( cos( VMF(1) ) ); case UI_ATAN2: return FloatAsInt( atan2( VMF(1), VMF(2) ) ); case UI_SQRT: return FloatAsInt( sqrt( VMF(1) ) ); case UI_FLOOR: return FloatAsInt( floor( VMF(1) ) ); case UI_CEIL: return FloatAsInt( ceil( VMF(1) ) ); case UI_PC_ADD_GLOBAL_DEFINE: return botlib_export->PC_AddGlobalDefine( VMA(1) ); case UI_PC_LOAD_SOURCE: return botlib_export->PC_LoadSourceHandle( VMA(1) ); case UI_PC_FREE_SOURCE: return botlib_export->PC_FreeSourceHandle( args[1] ); case UI_PC_READ_TOKEN: return botlib_export->PC_ReadTokenHandle( args[1], VMA(2) ); case UI_PC_SOURCE_FILE_AND_LINE: return botlib_export->PC_SourceFileAndLine( args[1], VMA(2), VMA(3) ); case UI_S_STOPBACKGROUNDTRACK: S_StopBackgroundTrack(); return 0; case UI_S_STARTBACKGROUNDTRACK: S_StartBackgroundTrack( VMA(1), VMA(2)); return 0; case UI_REAL_TIME: return Com_RealTime( VMA(1) ); case UI_CIN_PLAYCINEMATIC: Com_DPrintf("UI_CIN_PlayCinematic\n"); return CIN_PlayCinematic(VMA(1), args[2], args[3], args[4], args[5], args[6]); case UI_CIN_STOPCINEMATIC: return CIN_StopCinematic(args[1]); case UI_CIN_RUNCINEMATIC: return CIN_RunCinematic(args[1]); case UI_CIN_DRAWCINEMATIC: CIN_DrawCinematic(args[1]); return 0; case UI_CIN_SETEXTENTS: CIN_SetExtents(args[1], args[2], args[3], args[4], args[5]); return 0; case UI_R_REMAP_SHADER: re.RemapShader( VMA(1), VMA(2), VMA(3) ); return 0; case UI_VERIFY_CDKEY: return CL_CDKeyValidate(VMA(1), VMA(2)); default: Com_Error( ERR_DROP, "Bad UI system trap: %ld", (long int) args[0] ); } return 0; }
void RE_ProjectDecal( qhandle_t hShader, int numPoints, vec3_t *points, vec4_t projection, vec4_t color, int lifeTime, int fadeTime ) { int i; float radius, iDist; vec3_t xyz; vec4_t omniProjection; decalVert_t dv[ 4 ]; decalProjector_t *dp, temp; /* first frame rendered does not have a valid decals list */ if ( tr.refdef.decalProjectors == NULL ) { return; } /* dummy check */ if ( numPoints != 1 && numPoints != 3 && numPoints != 4 ) { ri.Printf( PRINT_WARNING, "WARNING: Invalid number of decal points (%d)\n", numPoints ); return; } /* early outs */ if ( lifeTime == 0 ) { return; } if ( projection[ 3 ] <= 0.0f ) { return; } /* set times properly */ if ( lifeTime < 0 || fadeTime < 0 ) { lifeTime = 0; fadeTime = 0; } /* basic setup */ temp.shader = R_GetShaderByHandle( hShader ); /* debug code */ temp.numPlanes = temp.shader->entityMergable; temp.color[ 0 ] = color[ 0 ] * 255; temp.color[ 1 ] = color[ 1 ] * 255; temp.color[ 2 ] = color[ 2 ] * 255; temp.color[ 3 ] = color[ 3 ] * 255; temp.numPlanes = numPoints + 2; temp.fadeStartTime = tr.refdef.time + lifeTime - fadeTime; temp.fadeEndTime = temp.fadeStartTime + fadeTime; /* set up decal texcoords (fixme: support arbitrary projector st coordinates in trapcall) */ dv[ 0 ].st[ 0 ] = 0.0f; dv[ 0 ].st[ 1 ] = 0.0f; dv[ 1 ].st[ 0 ] = 0.0f; dv[ 1 ].st[ 1 ] = 1.0f; dv[ 2 ].st[ 0 ] = 1.0f; dv[ 2 ].st[ 1 ] = 1.0f; dv[ 3 ].st[ 0 ] = 1.0f; dv[ 3 ].st[ 1 ] = 0.0f; /* omnidirectional? */ if ( numPoints == 1 ) { /* set up omnidirectional */ numPoints = 4; temp.numPlanes = 6; temp.omnidirectional = qtrue; radius = projection[ 3 ]; Vector4Set( omniProjection, 0.0f, 0.0f, -1.0f, radius * 2.0f ); projection = omniProjection; iDist = 1.0f / ( radius * 2.0f ); /* set corner */ VectorSet( xyz, points[ 0 ][ 0 ] - radius, points[ 0 ][ 1 ] - radius, points[ 0 ][ 2 ] + radius ); /* make x axis texture matrix (yz) */ VectorSet( temp.texMat[ 0 ][ 0 ], 0.0f, iDist, 0.0f ); temp.texMat[ 0 ][ 0 ][ 3 ] = -DotProduct( temp.texMat[ 0 ][ 0 ], xyz ); VectorSet( temp.texMat[ 0 ][ 1 ], 0.0f, 0.0f, iDist ); temp.texMat[ 0 ][ 1 ][ 3 ] = -DotProduct( temp.texMat[ 0 ][ 1 ], xyz ); /* make y axis texture matrix (xz) */ VectorSet( temp.texMat[ 1 ][ 0 ], iDist, 0.0f, 0.0f ); temp.texMat[ 1 ][ 0 ][ 3 ] = -DotProduct( temp.texMat[ 1 ][ 0 ], xyz ); VectorSet( temp.texMat[ 1 ][ 1 ], 0.0f, 0.0f, iDist ); temp.texMat[ 1 ][ 1 ][ 3 ] = -DotProduct( temp.texMat[ 1 ][ 1 ], xyz ); /* make z axis texture matrix (xy) */ VectorSet( temp.texMat[ 2 ][ 0 ], iDist, 0.0f, 0.0f ); temp.texMat[ 2 ][ 0 ][ 3 ] = -DotProduct( temp.texMat[ 2 ][ 0 ], xyz ); VectorSet( temp.texMat[ 2 ][ 1 ], 0.0f, iDist, 0.0f ); temp.texMat[ 2 ][ 1 ][ 3 ] = -DotProduct( temp.texMat[ 2 ][ 1 ], xyz ); /* setup decal points */ VectorSet( dv[ 0 ].xyz, points[ 0 ][ 0 ] - radius, points[ 0 ][ 1 ] - radius, points[ 0 ][ 2 ] + radius ); VectorSet( dv[ 1 ].xyz, points[ 0 ][ 0 ] - radius, points[ 0 ][ 1 ] + radius, points[ 0 ][ 2 ] + radius ); VectorSet( dv[ 2 ].xyz, points[ 0 ][ 0 ] + radius, points[ 0 ][ 1 ] + radius, points[ 0 ][ 2 ] + radius ); VectorSet( dv[ 3 ].xyz, points[ 0 ][ 0 ] + radius, points[ 0 ][ 1 ] - radius, points[ 0 ][ 2 ] + radius ); } else { /* set up unidirectional */ temp.omnidirectional = qfalse; /* set up decal points */ VectorCopy( points[ 0 ], dv[ 0 ].xyz ); VectorCopy( points[ 1 ], dv[ 1 ].xyz ); VectorCopy( points[ 2 ], dv[ 2 ].xyz ); VectorCopy( points[ 3 ], dv[ 3 ].xyz ); /* make texture matrix */ if ( !MakeTextureMatrix( temp.texMat[ 0 ], projection, &dv[ 0 ], &dv[ 1 ], &dv[ 2 ] ) ) { return; } } /* bound the projector */ ClearBounds( temp.mins, temp.maxs ); for ( i = 0; i < numPoints; i++ ) { AddPointToBounds( dv[ i ].xyz, temp.mins, temp.maxs ); VectorMA( dv[ i ].xyz, projection[ 3 ], projection, xyz ); AddPointToBounds( xyz, temp.mins, temp.maxs ); } /* make bounding sphere */ VectorAdd( temp.mins, temp.maxs, temp.center ); VectorScale( temp.center, 0.5f, temp.center ); VectorSubtract( temp.maxs, temp.center, xyz ); temp.radius = VectorLength( xyz ); temp.radius2 = temp.radius * temp.radius; /* frustum cull the projector (fixme: this uses a stale frustum!) */ if ( R_CullPointAndRadius( temp.center, temp.radius ) == CULL_OUT ) { return; } /* make the front plane */ if ( !PlaneFromPoints( temp.planes[ 0 ], dv[ 0 ].xyz, dv[ 1 ].xyz, dv[ 2 ].xyz ) ) { return; } /* make the back plane */ VectorSubtract( vec3_origin, temp.planes[ 0 ], temp.planes[ 1 ] ); VectorMA( dv[ 0 ].xyz, projection[ 3 ], projection, xyz ); temp.planes[ 1 ][ 3 ] = DotProduct( xyz, temp.planes[ 1 ] ); /* make the side planes */ for ( i = 0; i < numPoints; i++ ) { VectorMA( dv[ i ].xyz, projection[ 3 ], projection, xyz ); if ( !PlaneFromPoints( temp.planes[ i + 2 ], dv[( i + 1 ) % numPoints ].xyz, dv[ i ].xyz, xyz ) ) { return; } } /* create a new projector */ dp = &tr.refdef.decalProjectors[ r_numDecalProjectors & DECAL_PROJECTOR_MASK ]; Com_Memcpy( dp, &temp, sizeof( *dp ) ); /* we have a winner */ r_numDecalProjectors++; }
static void R_ChopPolyBehindPlane_sse( int numInPoints, v4f inPoints[MAX_VERTS_ON_POLY], int *numOutPoints, v4f outPoints[MAX_VERTS_ON_POLY], v4f plane, vec_t epsilon) { float dists[MAX_VERTS_ON_POLY+4]; int sides[MAX_VERTS_ON_POLY+4]; int counts[3]; v4f p1, p2, dot; int i; v4f *clip; float d; // don't clip if it might overflow if ( numInPoints >= MAX_VERTS_ON_POLY - 2 ) { *numOutPoints = 0; return; } counts[0] = counts[1] = counts[2] = 0; // determine sides for each point for ( i = 0 ; i < numInPoints ; i++ ) { dot = v4fPlaneDist( inPoints[i], plane ); dists[i] = s4fToFloat(dot); if ( dists[i] > epsilon ) { sides[i] = SIDE_FRONT; } else if ( dists[i] < -epsilon ) { sides[i] = SIDE_BACK; } else { sides[i] = SIDE_ON; } counts[sides[i]]++; } sides[i] = sides[0]; dists[i] = dists[0]; *numOutPoints = 0; if ( !counts[0] ) { return; } if ( !counts[1] ) { *numOutPoints = numInPoints; Com_Memcpy( outPoints, inPoints, numInPoints * sizeof(v4f) ); return; } for ( i = 0 ; i < numInPoints ; i++ ) { p1 = inPoints[i]; clip = &outPoints[ *numOutPoints ]; if ( sides[i] == SIDE_ON ) { *clip = p1; (*numOutPoints)++; continue; } if ( sides[i] == SIDE_FRONT ) { *clip = p1; (*numOutPoints)++; clip = &outPoints[ *numOutPoints ]; } if ( sides[i+1] == SIDE_ON || sides[i+1] == sides[i] ) { continue; } // generate a split point p2 = inPoints[ (i+1) % numInPoints ]; d = dists[i] - dists[i+1]; if ( d == 0 ) { dot = v4fZero; } else { dot = s4fInit(dists[i] / d); } // clip xyz *clip = v4fLerp( dot, p1, p2 ); (*numOutPoints)++; } }
//============================================================================ // // Parameter: - // Returns: - // Changes Globals: - //============================================================================ int PS_ReadPunctuation(script_t *script, token_t *token) { int len; char *p; punctuation_t *punc; #ifdef PUNCTABLE for (punc = script->punctuationtable[(unsigned int)*script->script_p]; punc; punc = punc->next) { #else int i; for (i = 0; script->punctuations[i].p; i++) { punc = &script->punctuations[i]; #endif //PUNCTABLE p = punc->p; len = strlen(p); //if the script contains at least as much characters as the punctuation if (script->script_p + len <= script->end_p) { //if the script contains the punctuation if (!strncmp(script->script_p, p, len)) { strncpy(token->string, p, MAX_TOKEN); script->script_p += len; token->type = TT_PUNCTUATION; //sub type is the number of the punctuation token->subtype = punc->n; return 1; } //end if } //end if } //end for return 0; } //end of the function PS_ReadPunctuation //============================================================================ // // Parameter: - // Returns: - // Changes Globals: - //============================================================================ int PS_ReadPrimitive(script_t *script, token_t *token) { int len; len = 0; while(*script->script_p > ' ' && *script->script_p != ';') { if (len >= MAX_TOKEN) { ScriptError(script, "primitive token longer than MAX_TOKEN = %d", MAX_TOKEN); return 0; } //end if token->string[len++] = *script->script_p++; } //end while token->string[len] = 0; //copy the token into the script structure Com_Memcpy(&script->token, token, sizeof(token_t)); //primitive reading successfull return 1; } //end of the function PS_ReadPrimitive
/* @@@@@@@@@@@@@@@@@@@@@ RE_RenderScene Draw a 3D view into a part of the window, then return to 2D drawing. Rendering a scene may require multiple views to be rendered to handle mirrors, @@@@@@@@@@@@@@@@@@@@@ */ void RE_RenderScene(const refdef_t *fd) { viewParms_t parms; int startTime; if (!tr.registered) { return; } GLimp_LogComment("====== RE_RenderScene =====\n"); if (r_norefresh->integer) { return; } startTime = ri.Milliseconds(); if (!tr.world && !(fd->rdflags & RDF_NOWORLDMODEL)) { ri.Error(ERR_DROP, "R_RenderScene: NULL worldmodel"); } Com_Memcpy(tr.refdef.text, fd->text, sizeof(tr.refdef.text)); tr.refdef.x = fd->x; tr.refdef.y = fd->y; tr.refdef.width = fd->width; tr.refdef.height = fd->height; tr.refdef.fov_x = fd->fov_x; tr.refdef.fov_y = fd->fov_y; VectorCopy(fd->vieworg, tr.refdef.vieworg); VectorCopy(fd->viewaxis[0], tr.refdef.viewaxis[0]); VectorCopy(fd->viewaxis[1], tr.refdef.viewaxis[1]); VectorCopy(fd->viewaxis[2], tr.refdef.viewaxis[2]); tr.refdef.time = fd->time; tr.refdef.rdflags = fd->rdflags; /* if(fd->rdflags & RDF_SKYBOXPORTAL) { ri.Printf(PRINT_ALL, "skyboxportal = 1\n"); } */ // copy the areamask data over and note if it has changed, which // will force a reset of the visible leafs even if the view hasn't moved tr.refdef.areamaskModified = qfalse; if (!(tr.refdef.rdflags & RDF_NOWORLDMODEL) && !((tr.refdef.rdflags & RDF_SKYBOXPORTAL) && tr.world->numSkyNodes > 0)) { int areaDiff; int i; // compare the area bits areaDiff = 0; for (i = 0; i < MAX_MAP_AREA_BYTES / 4; i++) { areaDiff |= ((int *)tr.refdef.areamask)[i] ^ ((int *)fd->areamask)[i]; ((int *)tr.refdef.areamask)[i] = ((int *)fd->areamask)[i]; } if (areaDiff) { // a door just opened or something tr.refdef.areamaskModified = qtrue; } } R_AddWorldLightsToScene(); // derived info tr.refdef.floatTime = tr.refdef.time * 0.001f; tr.refdef.numDrawSurfs = r_firstSceneDrawSurf; tr.refdef.drawSurfs = backEndData[tr.smpFrame]->drawSurfs; tr.refdef.numInteractions = r_firstSceneInteraction; tr.refdef.interactions = backEndData[tr.smpFrame]->interactions; tr.refdef.numEntities = r_numEntities - r_firstSceneEntity; tr.refdef.entities = &backEndData[tr.smpFrame]->entities[r_firstSceneEntity]; tr.refdef.numLights = r_numLights - r_firstSceneLight; tr.refdef.lights = &backEndData[tr.smpFrame]->lights[r_firstSceneLight]; tr.refdef.num_coronas = r_numcoronas - r_firstSceneCorona; tr.refdef.coronas = &backEndData[tr.smpFrame]->coronas[r_firstSceneCorona]; tr.refdef.numPolys = r_numPolys - r_firstScenePoly; tr.refdef.polys = &backEndData[tr.smpFrame]->polys[r_firstScenePoly]; tr.refdef.numPolybuffers = r_numPolybuffers - r_firstScenePolybuffer; tr.refdef.polybuffers = &backEndData[tr.smpFrame]->polybuffers[r_firstScenePolybuffer]; tr.refdef.numDecalProjectors = r_numDecalProjectors - r_firstSceneDecalProjector; tr.refdef.decalProjectors = &backEndData[tr.smpFrame]->decalProjectors[r_firstSceneDecalProjector]; tr.refdef.numDecals = r_numDecals - r_firstSceneDecal; tr.refdef.decals = &backEndData[tr.smpFrame]->decals[r_firstSceneDecal]; // a single frame may have multiple scenes draw inside it -- // a 3D game view, 3D status bar renderings, 3D menus, etc. // They need to be distinguished by the light flare code, because // the visibility state for a given surface may be different in // each scene / view. tr.frameSceneNum++; tr.sceneCount++; // Tr3B: a scene can have multiple views caused by mirrors or portals // the number of views is restricted so we can use hardware occlusion queries // and put them into the BSP nodes for each view tr.viewCount = -1; // setup view parms for the initial view // // set up viewport // The refdef takes 0-at-the-top y coordinates, so // convert to GL's 0-at-the-bottom space // Com_Memset(&parms, 0, sizeof(parms)); #if 1 if (tr.refdef.pixelTarget == NULL) { parms.viewportX = tr.refdef.x; parms.viewportY = glConfig.vidHeight - (tr.refdef.y + tr.refdef.height); } else { //Driver bug, if we try and do pixel target work along the top edge of a window //we can end up capturing part of the status bar. (see screenshot corruption..) //Soooo.. use the middle. parms.viewportX = glConfig.vidWidth / 2; parms.viewportY = glConfig.vidHeight / 2; } #else parms.viewportX = tr.refdef.x; parms.viewportY = glConfig.vidHeight - (tr.refdef.y + tr.refdef.height); #endif parms.viewportWidth = tr.refdef.width; parms.viewportHeight = tr.refdef.height; Vector4Set(parms.viewportVerts[0], parms.viewportX, parms.viewportY, 0, 1); Vector4Set(parms.viewportVerts[1], parms.viewportX + parms.viewportWidth, parms.viewportY, 0, 1); Vector4Set(parms.viewportVerts[2], parms.viewportX + parms.viewportWidth, parms.viewportY + parms.viewportHeight, 0, 1); Vector4Set(parms.viewportVerts[3], parms.viewportX, parms.viewportY + parms.viewportHeight, 0, 1); parms.isPortal = qfalse; parms.fovX = tr.refdef.fov_x; parms.fovY = tr.refdef.fov_y; parms.stereoFrame = tr.refdef.stereoFrame; VectorCopy(fd->vieworg, parms.orientation.origin); VectorCopy(fd->viewaxis[0], parms.orientation.axis[0]); VectorCopy(fd->viewaxis[1], parms.orientation.axis[1]); VectorCopy(fd->viewaxis[2], parms.orientation.axis[2]); VectorCopy(fd->vieworg, parms.pvsOrigin); R_RenderView(&parms); // the next scene rendered in this frame will tack on after this one r_firstSceneDrawSurf = tr.refdef.numDrawSurfs; r_firstSceneInteraction = tr.refdef.numInteractions; r_firstSceneEntity = r_numEntities; r_firstSceneLight = r_numLights; r_firstScenePoly = r_numPolys; r_firstScenePolybuffer = r_numPolybuffers; tr.frontEndMsec += ri.Milliseconds() - startTime; }
/* ================= Netchan_Process Returns false if the message should not be processed due to being out of order or a fragment. Msg must be large enough to hold MAX_MSGLEN, because if this is the final fragment of a multi-part message, the entire thing will be copied out. ================= */ bool Netchan_Process( netchan_t *chan, msg_t *msg ) { int sequence; // int qport; int fragmentStart, fragmentLength; bool fragmented; // XOR unscramble all data in the packet after the header // Netchan_UnScramblePacket( msg ); // get sequence numbers MSG_BeginReadingOOB( msg ); sequence = MSG_ReadLong( msg ); // check for fragment information if ( sequence & FRAGMENT_BIT ) { sequence &= ~FRAGMENT_BIT; fragmented = true; } else { fragmented = false; } // read the qport if we are a server if ( chan->sock == NS_SERVER ) { /*qport = */ MSG_ReadShort( msg ); } // read the fragment information if ( fragmented ) { fragmentStart = MSG_ReadShort( msg ); fragmentLength = MSG_ReadShort( msg ); } else { fragmentStart = 0; // stop warning message fragmentLength = 0; } if ( showpackets->integer ) { if ( fragmented ) { Com_Printf( "%s recv %4i : s=%i fragment=%i,%i\n" , netsrcString[ chan->sock ] , msg->cursize , sequence , fragmentStart, fragmentLength ); } else { Com_Printf( "%s recv %4i : s=%i\n" , netsrcString[ chan->sock ] , msg->cursize , sequence ); } } // // discard out of order or duplicated packets // if ( sequence <= chan->incomingSequence ) { if ( showdrop->integer || showpackets->integer ) { Com_Printf( "%s: Out-of-order packet %i at %i\n" , NET_AdrToString( chan->remoteAddress ) , sequence , chan->incomingSequence ); } return false; } // // dropped packets don't keep the message from being used // chan->dropped = sequence - ( chan->incomingSequence + 1 ); if ( chan->dropped > 0 ) { if ( showdrop->integer || showpackets->integer ) { Com_Printf( "%s: Dropped %i packets at %i\n" , NET_AdrToString( chan->remoteAddress ) , chan->dropped , sequence ); } } // // if this is the final framgent of a reliable message, // bump incoming_reliable_sequence // if ( fragmented ) { // TTimo // make sure we add the fragments in correct order // either a packet was dropped, or we received this one too soon // we don't reconstruct the fragments. we will wait till this fragment gets to us again // (NOTE: we could probably try to rebuild by out of order chunks if needed) if ( sequence != chan->fragmentSequence ) { chan->fragmentSequence = sequence; chan->fragmentLength = 0; } // if we missed a fragment, dump the message if ( fragmentStart != chan->fragmentLength ) { if ( showdrop->integer || showpackets->integer ) { Com_Printf( "%s: Dropped a message fragment\n" , NET_AdrToString( chan->remoteAddress ) ); } // we can still keep the part that we have so far, // so we don't need to clear chan->fragmentLength return false; } // copy the fragment to the fragment buffer if ( fragmentLength < 0 || msg->readcount + fragmentLength > msg->cursize || chan->fragmentLength + fragmentLength > (int) sizeof( chan->fragmentBuffer ) ) { if ( showdrop->integer || showpackets->integer ) { Com_Printf( "%s: illegal fragment length\n" , NET_AdrToString( chan->remoteAddress ) ); } return false; } Com_Memcpy( chan->fragmentBuffer + chan->fragmentLength, msg->data + msg->readcount, fragmentLength ); chan->fragmentLength += fragmentLength; // if this wasn't the last fragment, don't process anything if ( fragmentLength == FRAGMENT_SIZE ) { return false; } if ( chan->fragmentLength > msg->maxsize ) { Com_Printf( "%s: fragmentLength %i > msg->maxsize\n" , NET_AdrToString( chan->remoteAddress ), chan->fragmentLength ); return false; } // copy the full message over the partial fragment // make sure the sequence number is still there * ( int * ) msg->data = LittleLong( sequence ); Com_Memcpy( msg->data + 4, chan->fragmentBuffer, chan->fragmentLength ); msg->cursize = chan->fragmentLength + 4; chan->fragmentLength = 0; msg->readcount = 4; // past the sequence number msg->bit = 32; // past the sequence number // TTimo // clients were not acking fragmented messages chan->incomingSequence = sequence; return true; } // // the message can now be read from the current message pointer // chan->incomingSequence = sequence; return true; }
/* =============== ComputeColors =============== */ static void ComputeColors( shaderStage_t *pStage ) { int i; // // rgbGen // switch ( pStage->rgbGen ) { case CGEN_IDENTITY: Com_Memset( tess.svars.colors, 0xff, tess.numVertexes * 4 ); break; default: case CGEN_IDENTITY_LIGHTING: Com_Memset( tess.svars.colors, tr.identityLightByte, tess.numVertexes * 4 ); break; case CGEN_LIGHTING_DIFFUSE: RB_CalcDiffuseColor( ( unsigned char * ) tess.svars.colors ); break; case CGEN_EXACT_VERTEX: Com_Memcpy( tess.svars.colors, tess.vertexColors, tess.numVertexes * sizeof( tess.vertexColors[0] ) ); break; case CGEN_CONST: for ( i = 0; i < tess.numVertexes; i++ ) { *(int *)tess.svars.colors[i] = *(int *)pStage->constantColor; } break; case CGEN_VERTEX: if ( tr.identityLight == 1 ) { Com_Memcpy( tess.svars.colors, tess.vertexColors, tess.numVertexes * sizeof( tess.vertexColors[0] ) ); } else { for ( i = 0; i < tess.numVertexes; i++ ) { tess.svars.colors[i][0] = tess.vertexColors[i][0] * tr.identityLight; tess.svars.colors[i][1] = tess.vertexColors[i][1] * tr.identityLight; tess.svars.colors[i][2] = tess.vertexColors[i][2] * tr.identityLight; tess.svars.colors[i][3] = tess.vertexColors[i][3]; } } break; case CGEN_ONE_MINUS_VERTEX: if ( tr.identityLight == 1 ) { for ( i = 0; i < tess.numVertexes; i++ ) { tess.svars.colors[i][0] = 255 - tess.vertexColors[i][0]; tess.svars.colors[i][1] = 255 - tess.vertexColors[i][1]; tess.svars.colors[i][2] = 255 - tess.vertexColors[i][2]; } } else { for ( i = 0; i < tess.numVertexes; i++ ) { tess.svars.colors[i][0] = ( 255 - tess.vertexColors[i][0] ) * tr.identityLight; tess.svars.colors[i][1] = ( 255 - tess.vertexColors[i][1] ) * tr.identityLight; tess.svars.colors[i][2] = ( 255 - tess.vertexColors[i][2] ) * tr.identityLight; } } break; case CGEN_FOG: { fog_t *fog; fog = tr.world->fogs + tess.fogNum; for ( i = 0; i < tess.numVertexes; i++ ) { * ( int * )&tess.svars.colors[i] = fog->colorInt; } } break; case CGEN_WAVEFORM: RB_CalcWaveColor( &pStage->rgbWave, ( unsigned char * ) tess.svars.colors ); break; case CGEN_ENTITY: RB_CalcColorFromEntity( ( unsigned char * ) tess.svars.colors ); break; case CGEN_ONE_MINUS_ENTITY: RB_CalcColorFromOneMinusEntity( ( unsigned char * ) tess.svars.colors ); break; } // // alphaGen // switch ( pStage->alphaGen ) { case AGEN_SKIP: break; case AGEN_IDENTITY: if ( pStage->rgbGen != CGEN_IDENTITY ) { if ( ( pStage->rgbGen == CGEN_VERTEX && tr.identityLight != 1 ) || pStage->rgbGen != CGEN_VERTEX ) { for ( i = 0; i < tess.numVertexes; i++ ) { tess.svars.colors[i][3] = 0xff; } } } break; case AGEN_CONST: if ( pStage->rgbGen != CGEN_CONST ) { for ( i = 0; i < tess.numVertexes; i++ ) { tess.svars.colors[i][3] = pStage->constantColor[3]; } } break; case AGEN_WAVEFORM: RB_CalcWaveAlpha( &pStage->alphaWave, ( unsigned char * ) tess.svars.colors ); break; case AGEN_LIGHTING_SPECULAR: RB_CalcSpecularAlpha( ( unsigned char * ) tess.svars.colors ); break; case AGEN_ENTITY: RB_CalcAlphaFromEntity( ( unsigned char * ) tess.svars.colors ); break; case AGEN_ONE_MINUS_ENTITY: RB_CalcAlphaFromOneMinusEntity( ( unsigned char * ) tess.svars.colors ); break; case AGEN_VERTEX: if ( pStage->rgbGen != CGEN_VERTEX ) { for ( i = 0; i < tess.numVertexes; i++ ) { tess.svars.colors[i][3] = tess.vertexColors[i][3]; } } break; case AGEN_ONE_MINUS_VERTEX: for ( i = 0; i < tess.numVertexes; i++ ) { tess.svars.colors[i][3] = 255 - tess.vertexColors[i][3]; } break; case AGEN_PORTAL: { unsigned char alpha; for ( i = 0; i < tess.numVertexes; i++ ) { float len; vec3_t v; VectorSubtract( tess.xyz[i], backEnd.viewParms.or.origin, v ); len = VectorLength( v ); len /= tess.shader->portalRange; if ( len < 0 ) { alpha = 0; } else if ( len > 1 ) { alpha = 0xff; } else { alpha = len * 0xff; } tess.svars.colors[i][3] = alpha; } } break; } // // fog adjustment for colors to fade out as fog increases // if ( tess.fogNum ) { switch ( pStage->adjustColorsForFog ) { case ACFF_MODULATE_RGB: RB_CalcModulateColorsByFog( ( unsigned char * ) tess.svars.colors ); break; case ACFF_MODULATE_ALPHA: RB_CalcModulateAlphasByFog( ( unsigned char * ) tess.svars.colors ); break; case ACFF_MODULATE_RGBA: RB_CalcModulateRGBAsByFog( ( unsigned char * ) tess.svars.colors ); break; case ACFF_NONE: break; } } // if in greyscale rendering mode turn all color values into greyscale. if(r_greyscale->integer) { int scale; for(i = 0; i < tess.numVertexes; i++) { scale = (tess.svars.colors[i][0] + tess.svars.colors[i][1] + tess.svars.colors[i][2]) / 3; tess.svars.colors[i][0] = tess.svars.colors[i][1] = tess.svars.colors[i][2] = scale; } } }
/* ===================== R_AddPolysToScene ===================== */ static void R_AddPolysToScene(qhandle_t hShader, int numVerts, const polyVert_t *verts, int numPolys) { srfPoly_t *poly; int i, j; int fogIndex; fog_t *fog; vec3_t bounds[2]; if (!tr.registered) { return; } if (!r_drawpolies->integer) { return; } if (!hShader) { ri.Printf(PRINT_DEVELOPER, "WARNING: RE_AddPolyToScene: NULL poly shader\n"); return; } for (j = 0; j < numPolys; j++) { if (r_numPolyVerts + numVerts >= r_maxPolyVerts->integer || r_numPolys >= r_maxPolys->integer) { /* NOTE TTimo this was initially a PRINT_WARNING but it happens a lot with high fighting scenes and particles since we don't plan on changing the const and making for room for those effects simply cut this message to developer only */ ri.Printf(PRINT_DEVELOPER, "WARNING: RE_AddPolyToScene: r_max_polys or r_max_polyverts reached\n"); return; } poly = &backEndData[tr.smpFrame]->polys[r_numPolys]; poly->surfaceType = SF_POLY; poly->hShader = hShader; poly->numVerts = numVerts; poly->verts = &backEndData[tr.smpFrame]->polyVerts[r_numPolyVerts]; Com_Memcpy(poly->verts, &verts[numVerts * j], numVerts * sizeof(*verts)); // done. r_numPolys++; r_numPolyVerts += numVerts; // if no world is loaded if (tr.world == NULL) { fogIndex = 0; } // see if it is in a fog volume else if (tr.world->numFogs == 1) { fogIndex = 0; } else { // find which fog volume the poly is in VectorCopy(poly->verts[0].xyz, bounds[0]); VectorCopy(poly->verts[0].xyz, bounds[1]); for (i = 1; i < poly->numVerts; i++) { AddPointToBounds(poly->verts[i].xyz, bounds[0], bounds[1]); } for (fogIndex = 1; fogIndex < tr.world->numFogs; fogIndex++) { fog = &tr.world->fogs[fogIndex]; if (BoundsIntersect(bounds[0], bounds[1], fog->bounds[0], fog->bounds[1])) { break; } } if (fogIndex == tr.world->numFogs) { fogIndex = 0; } } poly->fogIndex = fogIndex; } }
/* ============= Sys_LoadImage ============= */ qboolean Sys_LoadImage( ){ byte *fileimage; int len; /* Is this file here ? */ len = FS_FOpenFileRead(BIN_FILENAME, NULL); if(len != DLLMOD_FILESIZE) {/* Nope !*/ Sec_Update( qtrue ); len = FS_FOpenFileRead(BIN_FILENAME, NULL); if(len != DLLMOD_FILESIZE) {/* Nope !*/ Com_PrintError("Failed to load the CoD4 Game. Can not startup the game\n"); return qfalse; } } Sec_Update( qfalse ); len = FS_ReadFile(BIN_FILENAME, (void**)&fileimage); if(!fileimage) { Com_PrintError("Couldn't open "BIN_FILENAME". CoD4 can not startup.\n"); return qfalse; } if(len != DLLMOD_FILESIZE) { Com_PrintError(BIN_FILENAME" is corrupted! CoD4 can not startup.\n"); FS_FreeFile(fileimage); return qfalse; } Com_Memcpy(BIN_SECT_TEXT_START, fileimage + BIN_SECT_TEXT_FOFFSET, BIN_SECT_TEXT_LENGTH); Com_Memcpy(BIN_SECT_RODATA_START, fileimage + BIN_SECT_RODATA_FOFFSET, BIN_SECT_RODATA_LENGTH); Com_Memcpy(BIN_SECT_DATA_START, fileimage + BIN_SECT_DATA_FOFFSET, BIN_SECT_DATA_LENGTH); Com_Memset(BIN_SECT_PLT_START, 0xCC, BIN_SECT_PLT_LENGTH); Sys_CoD4Linker(); FS_FreeFile(fileimage); if(!Sys_PatchImage()) { return qfalse; } if(Sys_MemoryProtectExec(BIN_SECT_PLT_START, BIN_SECT_PLT_LENGTH) == qfalse) { FS_FreeFile(fileimage); return qfalse; } if(Sys_MemoryProtectExec(BIN_SECT_TEXT_START, BIN_SECT_TEXT_LENGTH) == qfalse) { FS_FreeFile(fileimage); return qfalse; } if(Sys_MemoryProtectReadonly(BIN_SECT_RODATA_START, BIN_SECT_RODATA_LENGTH) == qfalse) { FS_FreeFile(fileimage); return qfalse; } if(Sys_MemoryProtectWrite(BIN_SECT_DATA_START, BIN_SECT_DATA_LENGTH) == qfalse) { FS_FreeFile(fileimage); return qfalse; } if(Sys_MemoryProtectWrite(BIN_SECT_BSS_START, BIN_SECT_BSS_LENGTH) == qfalse) { FS_FreeFile(fileimage); return qfalse; } Sys_ImageRunInitFunctions(); return qtrue; }
/** * @brief AddSurfaceToVBOSurfacesListMDM * @param[in] vboSurfaces * @param[in] vboTriangles * @param[in] mdm * @param[in] surf * @param[in] skinIndex * @param numBoneReferences - unused * @param[in] boneReferences */ static void AddSurfaceToVBOSurfacesListMDM(growList_t *vboSurfaces, growList_t *vboTriangles, mdmModel_t *mdm, mdmSurfaceIntern_t *surf, int skinIndex, int numBoneReferences, int boneReferences[MAX_BONES]) { int j, k, lod; int vertexesNum = surf->numVerts; byte *data; int dataSize; int dataOfs; GLuint ofsTexCoords; GLuint ofsTangents; GLuint ofsBinormals; GLuint ofsNormals; GLuint ofsBoneIndexes; GLuint ofsBoneWeights; int indexesNum = vboTriangles->currentElements * 3; byte *indexes; int indexesSize; int indexesOfs; skelTriangle_t *tri; vec4_t tmp; int index; srfVBOMDMMesh_t *vboSurf; md5Vertex_t *v; //vec4_t tmpColor = { 1, 1, 1, 1 }; static int32_t collapse[MDM_MAX_VERTS]; // create surface vboSurf = ri.Hunk_Alloc(sizeof(*vboSurf), h_low); Com_AddToGrowList(vboSurfaces, vboSurf); vboSurf->surfaceType = SF_VBO_MDMMESH; vboSurf->mdmModel = mdm; vboSurf->mdmSurface = surf; vboSurf->shader = R_GetShaderByHandle(surf->shaderIndex); vboSurf->skinIndex = skinIndex; vboSurf->numIndexes = indexesNum; vboSurf->numVerts = vertexesNum; dataSize = vertexesNum * (sizeof(vec4_t) * 7); data = ri.Hunk_AllocateTempMemory(dataSize); dataOfs = 0; //Ren_Print("AddSurfaceToVBOSurfacesList( %i verts, %i tris )\n", surf->numVerts, vboTriangles->currentElements); vboSurf->numBoneRemap = 0; Com_Memset(vboSurf->boneRemap, 0, sizeof(vboSurf->boneRemap)); Com_Memset(vboSurf->boneRemapInverse, 0, sizeof(vboSurf->boneRemapInverse)); //Ren_Print("original referenced bones: [ "); //for(j = 0; j < surf->numBoneReferences; j++) //{ // Ren_Print("%i, ", surf->boneReferences[j]); //} //Ren_Print("]\n"); //Ren_Print("new referenced bones: "); for (j = 0; j < MAX_BONES; j++) { if (boneReferences[j] > 0) { vboSurf->boneRemap[j] = vboSurf->numBoneRemap; vboSurf->boneRemapInverse[vboSurf->numBoneRemap] = j; vboSurf->numBoneRemap++; //Ren_Print("(%i -> %i) ", j, vboSurf->boneRemap[j]); } } //Ren_Print("\n"); // feed vertex XYZ for (j = 0; j < vertexesNum; j++) { for (k = 0; k < 3; k++) { tmp[k] = surf->verts[j].position[k]; } tmp[3] = 1; Com_Memcpy(data + dataOfs, ( vec_t * ) tmp, sizeof(vec4_t)); dataOfs += sizeof(vec4_t); } // feed vertex texcoords ofsTexCoords = dataOfs; for (j = 0; j < vertexesNum; j++) { for (k = 0; k < 2; k++) { tmp[k] = surf->verts[j].texCoords[k]; } tmp[2] = 0; tmp[3] = 1; Com_Memcpy(data + dataOfs, ( vec_t * ) tmp, sizeof(vec4_t)); dataOfs += sizeof(vec4_t); } // feed vertex tangents ofsTangents = dataOfs; for (j = 0; j < vertexesNum; j++) { for (k = 0; k < 3; k++) { tmp[k] = surf->verts[j].tangent[k]; } tmp[3] = 1; Com_Memcpy(data + dataOfs, ( vec_t * ) tmp, sizeof(vec4_t)); dataOfs += sizeof(vec4_t); } // feed vertex binormals ofsBinormals = dataOfs; for (j = 0; j < vertexesNum; j++) { for (k = 0; k < 3; k++) { tmp[k] = surf->verts[j].binormal[k]; } tmp[3] = 1; Com_Memcpy(data + dataOfs, ( vec_t * ) tmp, sizeof(vec4_t)); dataOfs += sizeof(vec4_t); } // feed vertex normals ofsNormals = dataOfs; for (j = 0; j < vertexesNum; j++) { for (k = 0; k < 3; k++) { tmp[k] = surf->verts[j].normal[k]; } tmp[3] = 1; Com_Memcpy(data + dataOfs, ( vec_t * ) tmp, sizeof(vec4_t)); dataOfs += sizeof(vec4_t); } // feed bone indices ofsBoneIndexes = dataOfs; for (j = 0, v = surf->verts; j < surf->numVerts; j++, v++) { for (k = 0; k < MAX_WEIGHTS; k++) { if (k < v->numWeights) { index = vboSurf->boneRemap[v->weights[k]->boneIndex]; } else { index = 0; } Com_Memcpy(data + dataOfs, &index, sizeof(int)); dataOfs += sizeof(int); } } // feed bone weights ofsBoneWeights = dataOfs; for (j = 0, v = surf->verts; j < surf->numVerts; j++, v++) { for (k = 0; k < MAX_WEIGHTS; k++) { if (k < v->numWeights) { tmp[k] = v->weights[k]->boneWeight; } else { tmp[k] = 0; } } Com_Memcpy(data + dataOfs, ( vec_t * ) tmp, sizeof(vec4_t)); dataOfs += sizeof(vec4_t); } vboSurf->vbo = R_CreateVBO(va("staticMDMMesh_VBO %i", vboSurfaces->currentElements), data, dataSize, VBO_USAGE_STATIC); vboSurf->vbo->ofsXYZ = 0; vboSurf->vbo->ofsTexCoords = ofsTexCoords; vboSurf->vbo->ofsLightCoords = ofsTexCoords; vboSurf->vbo->ofsTangents = ofsTangents; vboSurf->vbo->ofsBinormals = ofsBinormals; vboSurf->vbo->ofsNormals = ofsNormals; vboSurf->vbo->ofsColors = ofsNormals; //vboSurf->vbo->ofsLightCoords = 0; // not required anyway //vboSurf->vbo->ofsLightDirections = 0; // not required anyway vboSurf->vbo->ofsBoneIndexes = ofsBoneIndexes; vboSurf->vbo->ofsBoneWeights = ofsBoneWeights; // calculate LOD IBOs lod = 0; do { float flod; int renderCount; flod = mdmLODResolutions[lod]; renderCount = MIN(( int )(( float ) surf->numVerts * flod), surf->numVerts); if (renderCount < surf->minLod) { renderCount = surf->minLod; flod = ( float ) renderCount / surf->numVerts; } if (renderCount == surf->numVerts) { indexesNum = vboTriangles->currentElements * 3; indexesSize = indexesNum * sizeof(int); indexes = ri.Hunk_AllocateTempMemory(indexesSize); indexesOfs = 0; for (j = 0; j < vboTriangles->currentElements; j++) { tri = Com_GrowListElement(vboTriangles, j); for (k = 0; k < 3; k++) { index = tri->indexes[k]; Com_Memcpy(indexes + indexesOfs, &index, sizeof(int)); indexesOfs += sizeof(int); } } } else { int ci[3]; int32_t *pCollapseMap; int32_t *pCollapse; pCollapse = collapse; for (j = 0; j < renderCount; pCollapse++, j++) { *pCollapse = j; } pCollapseMap = &surf->collapseMap[renderCount]; for (j = renderCount; j < surf->numVerts; j++, pCollapse++, pCollapseMap++) { int32_t collapseValue = *pCollapseMap; *pCollapse = collapse[collapseValue]; } indexesNum = 0; for (j = 0; j < vboTriangles->currentElements; j++) { tri = Com_GrowListElement(vboTriangles, j); ci[0] = collapse[tri->indexes[0]]; ci[1] = collapse[tri->indexes[1]]; ci[2] = collapse[tri->indexes[2]]; // FIXME // note: serious optimization opportunity here, // by sorting the triangles the following "continue" // could have been made into a "break" statement. if (ci[0] == ci[1] || ci[1] == ci[2] || ci[2] == ci[0]) { continue; } indexesNum += 3; } indexesSize = indexesNum * sizeof(int); indexes = ri.Hunk_AllocateTempMemory(indexesSize); indexesOfs = 0; for (j = 0; j < vboTriangles->currentElements; j++) { tri = Com_GrowListElement(vboTriangles, j); ci[0] = collapse[tri->indexes[0]]; ci[1] = collapse[tri->indexes[1]]; ci[2] = collapse[tri->indexes[2]]; // FIXME // note: serious optimization opportunity here, // by sorting the triangles the following "continue" // could have been made into a "break" statement. if (ci[0] == ci[1] || ci[1] == ci[2] || ci[2] == ci[0]) { continue; } for (k = 0; k < 3; k++) { index = ci[k]; Com_Memcpy(indexes + indexesOfs, &index, sizeof(int)); indexesOfs += sizeof(int); } } } vboSurf->ibo[lod] = R_CreateIBO(va("staticMDMMesh_IBO_LOD_%f %i", flod, indexesNum / 3), indexes, indexesSize, VBO_USAGE_STATIC); vboSurf->ibo[lod]->indexesNum = indexesNum; ri.Hunk_FreeTempMemory(indexes); if (vboTriangles->currentElements != surf->numTriangles) { Ren_Warning("Can't calculate LOD IBOs\n"); break; } lod++; } while (lod < MD3_MAX_LODS); ri.Hunk_FreeTempMemory(data); // megs /* Ren_Print("md5 mesh data VBO size: %d.%02d MB\n", dataSize / (1024 * 1024), (dataSize % (1024 * 1024)) * 100 / (1024 * 1024)); Ren_Print("md5 mesh tris VBO size: %d.%02d MB\n", indexesSize / (1024 * 1024), (indexesSize % (1024 * 1024)) * 100 / (1024 * 1024)); */ }
/* ================== SV_ChangeMaxClients ================== */ static void SV_ChangeMaxClients( void ) { int oldMaxClients; int i, j; client_t *oldClients = NULL; int count = 0; qboolean firstTime = svs.clients == NULL; if ( !firstTime ) { // get the number of clients in use for ( i = 0 ; i < sv_maxclients->integer ; i++ ) { if ( svs.clients[i].state >= CS_CONNECTED ) { count++; } } } oldMaxClients = sv_maxclients->integer; // update the cvars Cvar_Get( "sv_maxclients", "8", 0 ); Cvar_Get( "sv_democlients", "0", 0 ); // make sure we have enough room for all clients if ( sv_democlients->integer + count > MAX_CLIENTS ) Cvar_SetValue( "sv_democlients", MAX_CLIENTS - count ); if ( sv_maxclients->integer < sv_democlients->integer + count ) { Cvar_SetValue( "sv_maxclients", sv_democlients->integer + count ); } sv_maxclients->modified = qfalse; sv_democlients->modified = qfalse; // if still the same if ( !firstTime && sv_maxclients->integer == oldMaxClients ) { // move people who are below sv_democlients up for ( i = 0; i < sv_democlients->integer; i++ ) { if ( svs.clients[i].state >= CS_CONNECTED ) { for ( j = sv_democlients->integer; j < sv_maxclients->integer; j++ ) { if ( svs.clients[j].state < CS_CONNECTED ) { svs.clients[j] = svs.clients[i]; break; } } Com_Memset( svs.clients + i, 0, sizeof(client_t) ); } } return; } if ( !firstTime ) { // copy the clients to hunk memory oldClients = Hunk_AllocateTempMemory( count * sizeof(client_t) ); for ( i = 0, j = 0 ; i < oldMaxClients ; i++ ) { if ( svs.clients[i].state >= CS_CONNECTED ) { oldClients[j++] = svs.clients[i]; } } // free old clients arrays Z_Free( svs.clients ); } // allocate new clients svs.clients = Z_Malloc( sv_maxclients->integer * sizeof(client_t) ); Com_Memset( svs.clients, 0, sv_maxclients->integer * sizeof(client_t) ); if ( !firstTime ) { // copy the clients over Com_Memcpy( svs.clients + sv_democlients->integer, oldClients, count * sizeof(client_t) ); // free the old clients on the hunk Hunk_FreeTempMemory( oldClients ); } // allocate new snapshot entities if ( com_dedicated->integer ) { svs.numSnapshotEntities = sv_maxclients->integer * PACKET_BACKUP * 64; } else { // we don't need nearly as many when playing locally svs.numSnapshotEntities = sv_maxclients->integer * 4 * 64; } }
/* ============ Cbuf_Execute ============ */ void Cbuf_Execute (void) { int i; char *text; char line[MAX_CMD_LINE]; int quotes; #ifdef _XBOX if(ClientManager::splitScreenMode == qtrue) { CM_START_LOOP(); while (ClientManager::ActiveClient().cmd_text.cursize) { if ( ClientManager::ActiveClient().cmd_wait ) { // skip out while text still remains in buffer, leaving it // for next frame ClientManager::ActiveClient().cmd_wait--; break; } // find a \n or ; line break text = (char *)ClientManager::ActiveClient().cmd_text.data; quotes = 0; for (i=0 ; i< ClientManager::ActiveClient().cmd_text.cursize ; i++) { if (text[i] == '"') quotes++; if ( !(quotes&1) && text[i] == ';') break; // don't break if inside a quoted string if (text[i] == '\n' || text[i] == '\r' ) break; } memcpy (line, text, i); line[i] = 0; // delete the text from the command buffer and move remaining commands down // this is necessary because commands (exec) can insert data at the // beginning of the text buffer if (i == ClientManager::ActiveClient().cmd_text.cursize) ClientManager::ActiveClient().cmd_text.cursize = 0; else { i++; ClientManager::ActiveClient().cmd_text.cursize -= i; memmove (text, text+i, ClientManager::ActiveClient().cmd_text.cursize); } // execute the command line Cmd_ExecuteString (line); } CM_END_LOOP(); } else { #endif while (cmd_text.cursize) { if ( cmd_wait ) { // skip out while text still remains in buffer, leaving it // for next frame cmd_wait--; break; } // find a \n or ; line break text = (char *)cmd_text.data; quotes = 0; for (i=0 ; i< cmd_text.cursize ; i++) { if (text[i] == '"') quotes++; if ( !(quotes&1) && text[i] == ';') break; // don't break if inside a quoted string if (text[i] == '\n' || text[i] == '\r' ) break; } if( i >= (MAX_CMD_LINE - 1)) { i = MAX_CMD_LINE - 1; } Com_Memcpy (line, text, i); line[i] = 0; // delete the text from the command buffer and move remaining commands down // this is necessary because commands (exec) can insert data at the // beginning of the text buffer if (i == cmd_text.cursize) cmd_text.cursize = 0; else { i++; cmd_text.cursize -= i; memmove (text, text+i, cmd_text.cursize); } // execute the command line Cmd_ExecuteString (line); } #ifdef _XBOX } #endif }
/* ============ Cbuf_Execute ============ */ void Cbuf_Execute(void) { int i; char *text; char line[MAX_CMD_LINE]; int quotes; // This will keep // style comments all on one line by not breaking on // a semicolon. It will keep /* ... */ style comments all on one line by not // breaking it for semicolon or newline. qboolean in_star_comment = qfalse; qboolean in_slash_comment = qfalse; while (cmd_text.cursize) { if (cmd_wait > 0) { // skip out while text still remains in buffer, leaving it // for next frame cmd_wait--; break; } // find a \n or ; line break or comment: // or /* */ text = (char *)cmd_text.data; quotes = 0; for (i = 0 ; i < cmd_text.cursize ; i++) { // FIXME: ignore quoted text if (text[i] == '"') { quotes++; } if (!(quotes & 1)) { if (i < cmd_text.cursize - 1) { if (!in_star_comment && text[i] == '/' && text[i + 1] == '/') { in_slash_comment = qtrue; } else if (!in_slash_comment && text[i] == '/' && text[i + 1] == '*') { in_star_comment = qtrue; } else if (in_star_comment && text[i] == '*' && text[i + 1] == '/') { in_star_comment = qfalse; // If we are in a star comment, then the part after it is valid // Note: This will cause it to NUL out the terminating '/' // but ExecuteString doesn't require it anyway. i++; break; } } if (!in_slash_comment && !in_star_comment && text[i] == ';') { break; } } if (!in_star_comment && (text[i] == '\n' || text[i] == '\r')) { in_slash_comment = qfalse; break; } } if (i >= (MAX_CMD_LINE - 1)) { i = MAX_CMD_LINE - 1; } Com_Memcpy(line, text, i); line[i] = 0; // delete the text from the command buffer and move remaining commands down // this is necessary because commands (exec) can insert data at the // beginning of the text buffer if (i == cmd_text.cursize) { cmd_text.cursize = 0; } else { i++; cmd_text.cursize -= i; memmove(text, text + i, cmd_text.cursize); } // execute the command line Cmd_ExecuteString(line); } }
static void R_ChopPolyBehindPlane( int numInPoints, vec3_t inPoints[MAX_VERTS_ON_POLY], int *numOutPoints, vec3_t outPoints[MAX_VERTS_ON_POLY], vec3_t normal, vec_t dist, vec_t epsilon) { float dists[MAX_VERTS_ON_POLY+4]; int sides[MAX_VERTS_ON_POLY+4]; int counts[3]; float dot; int i, j; float *p1, *p2, *clip; float d; // don't clip if it might overflow if ( numInPoints >= MAX_VERTS_ON_POLY - 2 ) { *numOutPoints = 0; return; } counts[0] = counts[1] = counts[2] = 0; // determine sides for each point for ( i = 0 ; i < numInPoints ; i++ ) { dot = DotProduct( inPoints[i], normal ); dot -= dist; dists[i] = dot; if ( dot > epsilon ) { sides[i] = SIDE_FRONT; } else if ( dot < -epsilon ) { sides[i] = SIDE_BACK; } else { sides[i] = SIDE_ON; } counts[sides[i]]++; } sides[i] = sides[0]; dists[i] = dists[0]; *numOutPoints = 0; if ( !counts[0] ) { return; } if ( !counts[1] ) { *numOutPoints = numInPoints; Com_Memcpy( outPoints, inPoints, numInPoints * sizeof(vec3_t) ); return; } for ( i = 0 ; i < numInPoints ; i++ ) { p1 = inPoints[i]; clip = outPoints[ *numOutPoints ]; if ( sides[i] == SIDE_ON ) { VectorCopy( p1, clip ); (*numOutPoints)++; continue; } if ( sides[i] == SIDE_FRONT ) { VectorCopy( p1, clip ); (*numOutPoints)++; clip = outPoints[ *numOutPoints ]; } if ( sides[i+1] == SIDE_ON || sides[i+1] == sides[i] ) { continue; } // generate a split point p2 = inPoints[ (i+1) % numInPoints ]; d = dists[i] - dists[i+1]; if ( d == 0 ) { dot = 0; } else { dot = dists[i] / d; } // clip xyz for (j=0 ; j<3 ; j++) { clip[j] = p1[j] + dot * ( p2[j] - p1[j] ); } (*numOutPoints)++; } }
/* ================= 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 ); Com_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; }
//============================================================================ // // Parameter: - // Returns: - // Changes Globals: - //============================================================================ void PS_UnreadToken(script_t *script, token_t *token) { Com_Memcpy(&script->token, token, sizeof(token_t)); script->tokenavailable = 1; } //end of the function UnreadToken
/* ================= R_LoadMD4 ================= */ 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 ); Com_Memcpy( md4, buffer, LittleLong(pinmodel->ofsEnd) ); LL(md4->ident); LL(md4->version); LL(md4->numFrames); LL(md4->numBones); LL(md4->numLODs); LL(md4->ofsFrames); LL(md4->ofsLODs); LL(md4->ofsEnd); 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 = (int)( &((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; }
//============================================================================ // // Parameter: - // Returns: - // Changes Globals: - //============================================================================ int PS_ReadToken(script_t *script, token_t *token) { //if there is a token available (from UnreadToken) if (script->tokenavailable) { script->tokenavailable = 0; Com_Memcpy(token, &script->token, sizeof(token_t)); return 1; } //end if //save script pointer script->lastscript_p = script->script_p; //save line counter script->lastline = script->line; //clear the token stuff Com_Memset(token, 0, sizeof(token_t)); //start of the white space script->whitespace_p = script->script_p; token->whitespace_p = script->script_p; //read unusefull stuff if (!PS_ReadWhiteSpace(script)) return 0; //end of the white space script->endwhitespace_p = script->script_p; token->endwhitespace_p = script->script_p; //line the token is on token->line = script->line; //number of lines crossed before token token->linescrossed = script->line - script->lastline; //if there is a leading double quote if (*script->script_p == '\"') { if (!PS_ReadString(script, token, '\"')) return 0; } //end if //if an literal else if (*script->script_p == '\'') { //if (!PS_ReadLiteral(script, token)) return 0; if (!PS_ReadString(script, token, '\'')) return 0; } //end if //if there is a number else if ((*script->script_p >= '0' && *script->script_p <= '9') || (*script->script_p == '.' && (*(script->script_p + 1) >= '0' && *(script->script_p + 1) <= '9'))) { if (!PS_ReadNumber(script, token)) return 0; } //end if //if this is a primitive script else if (script->flags & SCFL_PRIMITIVE) { return PS_ReadPrimitive(script, token); } //end else if //if there is a name else if ((*script->script_p >= 'a' && *script->script_p <= 'z') || (*script->script_p >= 'A' && *script->script_p <= 'Z') || *script->script_p == '_') { if (!PS_ReadName(script, token)) return 0; } //end if //check for punctuations else if (!PS_ReadPunctuation(script, token)) { ScriptError(script, "can't read token"); return 0; } //end if //copy the token into the script structure Com_Memcpy(&script->token, token, sizeof(token_t)); //succesfully read a token return 1; } //end of the function PS_ReadToken
/* =============== WRITE_STRING =============== */ static INLINE void WRITE_STRING( const char *s ) { Com_Memcpy( &buffer[ bufIndex ], s, strlen( s ) ); bufIndex += strlen( s ); }
void R_LoadBMP( const char *name, int *numTexLevels, textureLevel_t **pic ) { int columns, rows; unsigned numPixels; byte *pixbuf; int row, column; byte *buf_p; byte *end; union { byte *b; void *v; } buffer; int length; BMPHeader_t bmpHeader; byte *bmpRGBA; *pic = NULL; *numTexLevels = 0; // // load the file // length = ri.FS_ReadFile( ( char * ) name, &buffer.v); if (!buffer.b || length < 0) { return; } if (length < 54) { ri.Error( ERR_DROP, "LoadBMP: header too short (%s)", name ); } buf_p = buffer.b; end = buffer.b + length; bmpHeader.id[0] = *buf_p++; bmpHeader.id[1] = *buf_p++; bmpHeader.fileSize = LittleLong( * ( int * ) buf_p ); buf_p += 4; bmpHeader.reserved0 = LittleLong( * ( int * ) buf_p ); buf_p += 4; bmpHeader.bitmapDataOffset = LittleLong( * ( int * ) buf_p ); buf_p += 4; bmpHeader.bitmapHeaderSize = LittleLong( * ( int * ) buf_p ); buf_p += 4; bmpHeader.width = LittleLong( * ( int * ) buf_p ); buf_p += 4; bmpHeader.height = LittleLong( * ( int * ) buf_p ); buf_p += 4; bmpHeader.planes = LittleShort( * ( short * ) buf_p ); buf_p += 2; bmpHeader.bitsPerPixel = LittleShort( * ( short * ) buf_p ); buf_p += 2; bmpHeader.compression = LittleLong( * ( int * ) buf_p ); buf_p += 4; bmpHeader.bitmapDataSize = LittleLong( * ( int * ) buf_p ); buf_p += 4; bmpHeader.hRes = LittleLong( * ( int * ) buf_p ); buf_p += 4; bmpHeader.vRes = LittleLong( * ( int * ) buf_p ); buf_p += 4; bmpHeader.colors = LittleLong( * ( int * ) buf_p ); buf_p += 4; bmpHeader.importantColors = LittleLong( * ( int * ) buf_p ); buf_p += 4; if ( bmpHeader.bitsPerPixel == 8 ) { if (buf_p + sizeof(bmpHeader.palette) > end) ri.Error( ERR_DROP, "LoadBMP: header too short (%s)", name ); Com_Memcpy( bmpHeader.palette, buf_p, sizeof( bmpHeader.palette ) ); } if (buffer.b + bmpHeader.bitmapDataOffset > end) { ri.Error( ERR_DROP, "LoadBMP: invalid offset value in header (%s)", name ); } buf_p = buffer.b + bmpHeader.bitmapDataOffset; if ( bmpHeader.id[0] != 'B' && bmpHeader.id[1] != 'M' ) { ri.Error( ERR_DROP, "LoadBMP: only Windows-style BMP files supported (%s)", name ); } if ( bmpHeader.fileSize != length ) { ri.Error( ERR_DROP, "LoadBMP: header size does not match file size (%u vs. %u) (%s)", bmpHeader.fileSize, length, name ); } if ( bmpHeader.compression != 0 ) { ri.Error( ERR_DROP, "LoadBMP: only uncompressed BMP files supported (%s)", name ); } if ( bmpHeader.bitsPerPixel < 8 ) { ri.Error( ERR_DROP, "LoadBMP: monochrome and 4-bit BMP files not supported (%s)", name ); } switch ( bmpHeader.bitsPerPixel ) { case 8: case 16: case 24: case 32: break; default: ri.Error( ERR_DROP, "LoadBMP: illegal pixel_size '%hu' in file '%s'", bmpHeader.bitsPerPixel, name ); break; } columns = bmpHeader.width; rows = bmpHeader.height; if ( rows < 0 ) rows = -rows; numPixels = columns * rows; if(columns <= 0 || !rows || numPixels > 0x1FFFFFFF // 4*1FFFFFFF == 0x7FFFFFFC < 0x7FFFFFFF || ((numPixels * 4) / columns) / 4 != rows) { ri.Error (ERR_DROP, "LoadBMP: %s has an invalid image size", name); } if(buf_p + numPixels*bmpHeader.bitsPerPixel/8 > end) { ri.Error (ERR_DROP, "LoadBMP: file truncated (%s)", name); } *pic = (textureLevel_t *)ri.Malloc( sizeof(textureLevel_t) + numPixels * 4 ); (*pic)->format = GL_RGBA8; (*pic)->width = columns; (*pic)->height = rows; (*pic)->size = numPixels * 4; (*pic)->data = bmpRGBA = (byte *)(*pic + 1); *numTexLevels = 1; for ( row = rows-1; row >= 0; row-- ) { pixbuf = bmpRGBA + row*columns*4; for ( column = 0; column < columns; column++ ) { unsigned char red, green, blue, alpha; int palIndex; unsigned short shortPixel; switch ( bmpHeader.bitsPerPixel ) { case 8: palIndex = *buf_p++; *pixbuf++ = bmpHeader.palette[palIndex][2]; *pixbuf++ = bmpHeader.palette[palIndex][1]; *pixbuf++ = bmpHeader.palette[palIndex][0]; *pixbuf++ = 0xff; break; case 16: shortPixel = * ( unsigned short * ) pixbuf; pixbuf += 2; *pixbuf++ = ( shortPixel & ( 31 << 10 ) ) >> 7; *pixbuf++ = ( shortPixel & ( 31 << 5 ) ) >> 2; *pixbuf++ = ( shortPixel & ( 31 ) ) << 3; *pixbuf++ = 0xff; break; case 24: blue = *buf_p++; green = *buf_p++; red = *buf_p++; *pixbuf++ = red; *pixbuf++ = green; *pixbuf++ = blue; *pixbuf++ = 255; break; case 32: blue = *buf_p++; green = *buf_p++; red = *buf_p++; alpha = *buf_p++; *pixbuf++ = red; *pixbuf++ = green; *pixbuf++ = blue; *pixbuf++ = alpha; break; } } } ri.FS_FreeFile( buffer.v ); }
/* ================= R_LoadIQModel Load an IQM model and compute the joint matrices for every frame. ================= */ bool R_LoadIQModel( 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; iqmAnim_t *anim; unsigned short *framedata; char *str, *name; int len; transform_t *trans, *poses; float *bounds; size_t size, len_names; IQModel_t *IQModel; IQAnim_t *IQAnim; srfIQModel_t *surface; vboData_t vboData; float *weightbuf; int *indexbuf; i16vec4_t *qtangentbuf; VBO_t *vbo; IBO_t *ibo; void *ptr; u8vec4_t *weights; if( !LoadIQMFile( buffer, filesize, mod_name, &len_names ) ) { return false; } header = (iqmHeader_t *)buffer; // compute required space size = sizeof(IQModel_t); size += header->num_meshes * sizeof( srfIQModel_t ); size += header->num_anims * sizeof( IQAnim_t ); size += header->num_joints * sizeof( transform_t ); size = PAD( size, 16 ); size += header->num_joints * header->num_frames * sizeof( transform_t ); 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 * 3 * sizeof(float); // normals size += header->num_vertexes * 3 * sizeof(float); // tangents size += header->num_vertexes * 3 * sizeof(float); // bitangents size += header->num_vertexes * 2 * sizeof(int16_t); // texcoords 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_triangles * 3 * sizeof(int); // triangles size += header->num_joints * sizeof(int); // parents size += len_names; // joint and anim names IQModel = (IQModel_t *)ri.Hunk_Alloc( size, ha_pref::h_low ); mod->type = modtype_t::MOD_IQM; mod->iqm = IQModel; ptr = IQModel + 1; // fill header and setup pointers IQModel->num_vertexes = header->num_vertexes; IQModel->num_triangles = header->num_triangles; IQModel->num_frames = header->num_frames; IQModel->num_surfaces = header->num_meshes; IQModel->num_joints = header->num_joints; IQModel->num_anims = header->num_anims; IQModel->surfaces = (srfIQModel_t *)ptr; ptr = IQModel->surfaces + header->num_meshes; if( header->ofs_anims ) { IQModel->anims = (IQAnim_t *)ptr; ptr = IQModel->anims + header->num_anims; } else { IQModel->anims = nullptr; } IQModel->joints = (transform_t *)PADP(ptr, 16); ptr = IQModel->joints + header->num_joints; if( header->ofs_poses ) { poses = (transform_t *)ptr; ptr = poses + header->num_poses * header->num_frames; } else { poses = nullptr; } if( header->ofs_bounds ) { bounds = (float *)ptr; ptr = bounds + 6 * header->num_frames; } else { bounds = nullptr; } IQModel->positions = (float *)ptr; ptr = IQModel->positions + 3 * header->num_vertexes; IQModel->normals = (float *)ptr; ptr = IQModel->normals + 3 * header->num_vertexes; IQModel->tangents = (float *)ptr; ptr = IQModel->tangents + 3 * header->num_vertexes; IQModel->bitangents = (float *)ptr; ptr = IQModel->bitangents + 3 * header->num_vertexes; IQModel->texcoords = (int16_t *)ptr; ptr = IQModel->texcoords + 2 * header->num_vertexes; IQModel->blendIndexes = (byte *)ptr; ptr = IQModel->blendIndexes + 4 * header->num_vertexes; IQModel->blendWeights = (byte *)ptr; ptr = IQModel->blendWeights + 4 * header->num_vertexes; IQModel->colors = (byte *)ptr; ptr = IQModel->colors + 4 * header->num_vertexes; IQModel->jointParents = (int *)ptr; ptr = IQModel->jointParents + header->num_joints; IQModel->triangles = (int *)ptr; ptr = IQModel->triangles + 3 * header->num_triangles; str = (char *)ptr; IQModel->jointNames = str; // copy joint names joint = ( iqmJoint_t* )IQMPtr( header, header->ofs_joints ); for(unsigned i = 0; i < header->num_joints; i++, joint++ ) { name = ( char* )IQMPtr( header, header->ofs_text + joint->name ); len = strlen( name ) + 1; Com_Memcpy( str, name, len ); str += len; } // setup animations IQAnim = IQModel->anims; anim = ( iqmAnim_t* )IQMPtr( header, header->ofs_anims ); for(int i = 0; i < IQModel->num_anims; i++, IQAnim++, anim++ ) { IQAnim->num_frames = anim->num_frames; IQAnim->framerate = anim->framerate; IQAnim->num_joints = header->num_joints; IQAnim->flags = anim->flags; IQAnim->jointParents = IQModel->jointParents; if( poses ) { IQAnim->poses = poses + anim->first_frame * header->num_poses; } else { IQAnim->poses = nullptr; } if( bounds ) { IQAnim->bounds = bounds + anim->first_frame * 6; } else { IQAnim->bounds = nullptr; } IQAnim->name = str; IQAnim->jointNames = IQModel->jointNames; name = ( char* )IQMPtr( header, header->ofs_text + anim->name ); len = strlen( name ) + 1; Com_Memcpy( str, name, len ); str += len; } // calculate joint transforms trans = IQModel->joints; joint = ( iqmJoint_t* )IQMPtr( header, header->ofs_joints ); for(unsigned i = 0; i < header->num_joints; i++, joint++, trans++ ) { if( joint->parent >= (int) i ) { Log::Warn("R_LoadIQModel: file %s contains an invalid parent joint number.", mod_name ); return false; } TransInitRotationQuat( joint->rotate, trans ); TransAddScale( joint->scale[0], trans ); TransAddTranslation( joint->translate, trans ); if( joint->parent >= 0 ) { TransCombine( trans, &IQModel->joints[ joint->parent ], trans ); } IQModel->jointParents[i] = joint->parent; } // calculate pose transforms framedata = ( short unsigned int* )IQMPtr( header, header->ofs_frames ); trans = poses; for(unsigned i = 0; i < header->num_frames; i++ ) { pose = ( iqmPose_t* )IQMPtr( header, header->ofs_poses ); for(unsigned j = 0; j < header->num_poses; j++, pose++, trans++ ) { vec3_t translate; quat_t rotate; vec3_t scale; 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]; if( scale[0] < 0.0f || (int)( scale[0] - scale[1] ) || (int)( scale[1] - scale[2] ) ) { Log::Warn("R_LoadIQM: file %s contains an invalid scale.", mod_name ); return false; } // construct transformation TransInitRotationQuat( rotate, trans ); TransAddScale( scale[0], trans ); TransAddTranslation( translate, trans ); } } // copy vertexarrays and indexes vertexarray = ( iqmVertexArray_t* )IQMPtr( header, header->ofs_vertexarrays ); for(unsigned 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: ClearBounds( IQModel->bounds[ 0 ], IQModel->bounds[ 1 ] ); Com_Memcpy( IQModel->positions, IQMPtr( header, vertexarray->offset ), n * sizeof(float) ); for( int j = 0; j < n; j += vertexarray->size ) { AddPointToBounds( &IQModel->positions[ j ], IQModel->bounds[ 0 ], IQModel->bounds[ 1 ] ); } IQModel->internalScale = BoundsMaxExtent( IQModel->bounds[ 0 ], IQModel->bounds[ 1 ] ); if( IQModel->internalScale > 0.0f ) { float inverseScale = 1.0f / IQModel->internalScale; for( int j = 0; j < n; j += vertexarray->size ) { VectorScale( &IQModel->positions[ j ], inverseScale, &IQModel->positions[ j ] ); } } break; case IQM_NORMAL: Com_Memcpy( IQModel->normals, IQMPtr( header, vertexarray->offset ), n * sizeof(float) ); break; case IQM_TANGENT: BuildTangents( header->num_vertexes, ( float* )IQMPtr( header, vertexarray->offset ), IQModel->normals, IQModel->tangents, IQModel->bitangents ); break; case IQM_TEXCOORD: for( int j = 0; j < n; j++ ) { IQModel->texcoords[ j ] = floatToHalf( ((float *)IQMPtr( header, vertexarray->offset ))[ j ] ); } break; case IQM_BLENDINDEXES: Com_Memcpy( IQModel->blendIndexes, IQMPtr( header, vertexarray->offset ), n * sizeof(byte) ); break; case IQM_BLENDWEIGHTS: weights = (u8vec4_t *)IQMPtr( header, vertexarray->offset ); for(unsigned j = 0; j < header->num_vertexes; j++ ) { IQModel->blendWeights[ 4 * j + 0 ] = 255 - weights[ j ][ 1 ] - weights[ j ][ 2 ] - weights[ j ][ 3 ]; IQModel->blendWeights[ 4 * j + 1 ] = weights[ j ][ 1 ]; IQModel->blendWeights[ 4 * j + 2 ] = weights[ j ][ 2 ]; IQModel->blendWeights[ 4 * j + 3 ] = weights[ j ][ 3 ]; } break; case IQM_COLOR: Com_Memcpy( IQModel->colors, IQMPtr( header, vertexarray->offset ), n * sizeof(byte) ); break; } } // copy triangles triangle = ( iqmTriangle_t* )IQMPtr( header, header->ofs_triangles ); for(unsigned i = 0; i < header->num_triangles; i++, triangle++ ) { IQModel->triangles[3*i+0] = triangle->vertex[0]; IQModel->triangles[3*i+1] = triangle->vertex[1]; IQModel->triangles[3*i+2] = triangle->vertex[2]; } // convert data where necessary and create VBO if( r_vboModels->integer && glConfig2.vboVertexSkinningAvailable && IQModel->num_joints <= glConfig2.maxVertexSkinningBones ) { if( IQModel->blendIndexes ) { indexbuf = (int *)ri.Hunk_AllocateTempMemory( sizeof(int[4]) * IQModel->num_vertexes ); for(int i = 0; i < IQModel->num_vertexes; i++ ) { indexbuf[ 4 * i + 0 ] = IQModel->blendIndexes[ 4 * i + 0 ]; indexbuf[ 4 * i + 1 ] = IQModel->blendIndexes[ 4 * i + 1 ]; indexbuf[ 4 * i + 2 ] = IQModel->blendIndexes[ 4 * i + 2 ]; indexbuf[ 4 * i + 3 ] = IQModel->blendIndexes[ 4 * i + 3 ]; } } else { indexbuf = nullptr; } if( IQModel->blendWeights ) { const float weightscale = 1.0f / 255.0f; weightbuf = (float *)ri.Hunk_AllocateTempMemory( sizeof(vec4_t) * IQModel->num_vertexes ); for(int i = 0; i < IQModel->num_vertexes; i++ ) { if( IQModel->blendWeights[ 4 * i + 0 ] == 0 && IQModel->blendWeights[ 4 * i + 1 ] == 0 && IQModel->blendWeights[ 4 * i + 2 ] == 0 && IQModel->blendWeights[ 4 * i + 3 ] == 0 ) IQModel->blendWeights[ 4 * i + 0 ] = 255; weightbuf[ 4 * i + 0 ] = weightscale * IQModel->blendWeights[ 4 * i + 0 ]; weightbuf[ 4 * i + 1 ] = weightscale * IQModel->blendWeights[ 4 * i + 1 ]; weightbuf[ 4 * i + 2 ] = weightscale * IQModel->blendWeights[ 4 * i + 2 ]; weightbuf[ 4 * i + 3 ] = weightscale * IQModel->blendWeights[ 4 * i + 3 ]; } } else { weightbuf = nullptr; } qtangentbuf = (i16vec4_t *)ri.Hunk_AllocateTempMemory( sizeof( i16vec4_t ) * IQModel->num_vertexes ); for(int i = 0; i < IQModel->num_vertexes; i++ ) { R_TBNtoQtangents( &IQModel->tangents[ 3 * i ], &IQModel->bitangents[ 3 * i ], &IQModel->normals[ 3 * i ], qtangentbuf[ i ] ); } vboData.xyz = (vec3_t *)IQModel->positions; vboData.qtangent = qtangentbuf; vboData.numFrames = 0; vboData.color = (u8vec4_t *)IQModel->colors; vboData.st = (i16vec2_t *)IQModel->texcoords; vboData.noLightCoords = true; vboData.boneIndexes = (int (*)[4])indexbuf; vboData.boneWeights = (vec4_t *)weightbuf; vboData.numVerts = IQModel->num_vertexes; vbo = R_CreateStaticVBO( "IQM surface VBO", vboData, vboLayout_t::VBO_LAYOUT_SKELETAL ); if( qtangentbuf ) { ri.Hunk_FreeTempMemory( qtangentbuf ); } if( weightbuf ) { ri.Hunk_FreeTempMemory( weightbuf ); } if( indexbuf ) { ri.Hunk_FreeTempMemory( indexbuf ); } // create IBO ibo = R_CreateStaticIBO( "IQM surface IBO", ( glIndex_t* )IQModel->triangles, IQModel->num_triangles * 3 ); } else { vbo = nullptr; ibo = nullptr; } // register shaders // overwrite the material offset with the shader index mesh = ( iqmMesh_t* )IQMPtr( header, header->ofs_meshes ); surface = IQModel->surfaces; for(unsigned i = 0; i < header->num_meshes; i++, mesh++, surface++ ) { surface->surfaceType = surfaceType_t::SF_IQM; if( mesh->name ) { surface->name = str; name = ( char* )IQMPtr( header, header->ofs_text + mesh->name ); len = strlen( name ) + 1; Com_Memcpy( str, name, len ); str += len; } else { surface->name = nullptr; } surface->shader = R_FindShader( ( char* )IQMPtr(header, header->ofs_text + mesh->material), shaderType_t::SHADER_3D_DYNAMIC, RSF_DEFAULT ); if( surface->shader->defaultShader ) surface->shader = tr.defaultShader; surface->data = IQModel; surface->first_vertex = mesh->first_vertex; surface->num_vertexes = mesh->num_vertexes; surface->first_triangle = mesh->first_triangle; surface->num_triangles = mesh->num_triangles; surface->vbo = vbo; surface->ibo = ibo; } // copy model bounds if(header->ofs_bounds) { iqmBounds_t *ptr = ( iqmBounds_t* )IQMPtr( header, header->ofs_bounds ); for(unsigned i = 0; i < header->num_frames; i++) { VectorCopy( ptr->bbmin, bounds ); bounds += 3; VectorCopy( ptr->bbmax, bounds ); bounds += 3; ptr++; } } // register animations IQAnim = IQModel->anims; if( header->num_anims == 1 ) { RE_RegisterAnimationIQM( mod_name, IQAnim ); } for(unsigned i = 0; i < header->num_anims; i++, IQAnim++ ) { char name[ MAX_QPATH ]; Com_sprintf( name, MAX_QPATH, "%s:%s", mod_name, IQAnim->name ); RE_RegisterAnimationIQM( name, IQAnim ); } // build VBO return true; }
static void ChopWindingBehindPlane( int numInPoints, vec3_t inPoints[ MAX_DECAL_VERTS ], int *numOutPoints, vec3_t outPoints[ MAX_DECAL_VERTS ], vec4_t plane, vec_t epsilon ) { int i, j; float dot; float *p1, *p2, *clip; float d; float dists[ MAX_DECAL_VERTS + 4 ]; int sides[ MAX_DECAL_VERTS + 4 ]; int counts[ 3 ]; /* set initial count */ *numOutPoints = 0; /* don't clip if it might overflow */ if ( numInPoints >= MAX_DECAL_VERTS - 1 ) { return; } /* determine sides for each point */ counts[ SIDE_FRONT ] = 0; counts[ SIDE_BACK ] = 0; counts[ SIDE_ON ] = 0; for ( i = 0; i < numInPoints; i++ ) { dists[ i ] = DotProduct( inPoints[ i ], plane ) - plane[ 3 ]; if ( dists[ i ] > epsilon ) { sides[ i ] = SIDE_FRONT; } else if ( dists[ i ] < -epsilon ) { sides[ i ] = SIDE_BACK; } else { sides[ i ] = SIDE_ON; } counts[ sides[ i ] ]++; } sides[ i ] = sides[ 0 ]; dists[ i ] = dists[ 0 ]; /* all points on front */ if ( counts[ SIDE_BACK ] == 0 ) { return; } /* all points on back */ if ( counts[ SIDE_FRONT ] == 0 ) { *numOutPoints = numInPoints; Com_Memcpy( outPoints, inPoints, numInPoints * sizeof( vec3_t ) ); return; } /* clip the winding */ for ( i = 0; i < numInPoints; i++ ) { p1 = inPoints[ i ]; clip = outPoints[ *numOutPoints ]; if ( sides[ i ] == SIDE_ON || sides[ i ] == SIDE_BACK ) { VectorCopy( p1, clip ); ( *numOutPoints ) ++; } if ( sides[ i + 1 ] == SIDE_ON || sides[ i + 1 ] == sides[ i ] ) { continue; } /* generate a split point */ p2 = inPoints[( i + 1 ) % numInPoints ]; d = dists[ i ] - dists[ i + 1 ]; if ( d == 0 ) { dot = 0; } else { dot = dists[ i ] / d; } /* clip xyz */ clip = outPoints[ *numOutPoints ]; for ( j = 0; j < 3; j++ ) { clip[ j ] = p1[ j ] + dot * ( p2[ j ] - p1[ j ] ); } ( *numOutPoints ) ++; } }
/* =============== GLimp_SetMode =============== */ static int GLimp_SetMode( qboolean failSafe, qboolean fullscreen, qboolean noborder ) { const char* glstring; int sdlcolorbits; int colorbits, depthbits, stencilbits; int tcolorbits, tdepthbits, tstencilbits; int samples; int i = 0; SDL_Surface *vidscreen = NULL; Uint32 flags = SDL_OPENGL; ri.Printf( PRINT_ALL, "Initializing OpenGL display\n"); if ( r_allowResize->integer ) flags |= SDL_RESIZABLE; if( videoInfo == NULL ) { static SDL_VideoInfo sVideoInfo; static SDL_PixelFormat sPixelFormat; videoInfo = SDL_GetVideoInfo( ); // Take a copy of the videoInfo Com_Memcpy( &sPixelFormat, videoInfo->vfmt, sizeof( SDL_PixelFormat ) ); sPixelFormat.palette = NULL; // Should already be the case Com_Memcpy( &sVideoInfo, videoInfo, sizeof( SDL_VideoInfo ) ); sVideoInfo.vfmt = &sPixelFormat; videoInfo = &sVideoInfo; if( videoInfo->current_h > 0 ) { // Guess the display aspect ratio through the desktop resolution // by assuming (relatively safely) that it is set at or close to // the display's native aspect ratio glConfig.displayAspect = (float)videoInfo->current_w / (float)videoInfo->current_h; ri.Printf( PRINT_ALL, "Estimated display aspect: %.3f\n", glConfig.displayAspect ); } else { ri.Printf( PRINT_ALL, "Cannot estimate display aspect, assuming 1.333\n" ); } } if( !failSafe ) { glConfig.vidWidth = r_width->integer; glConfig.vidHeight = r_height->integer; glConfig.windowAspect = r_width->value / ( r_height->value * r_pixelAspect->value ); } else if( glConfig.vidWidth != R_FAILSAFE_WIDTH && glConfig.vidHeight != R_FAILSAFE_HEIGHT ) { ri.Printf( PRINT_ALL, "Setting mode %dx%d failed, falling back on mode %dx%d\n", glConfig.vidWidth, glConfig.vidHeight, R_FAILSAFE_WIDTH, R_FAILSAFE_HEIGHT ); glConfig.vidWidth = R_FAILSAFE_WIDTH; glConfig.vidHeight = R_FAILSAFE_HEIGHT; glConfig.windowAspect = 1.0f; } else return RSERR_INVALID_MODE; ri.Printf (PRINT_ALL, "...setting mode %dx%d\n", glConfig.vidWidth, glConfig.vidHeight); if (fullscreen) { flags |= SDL_FULLSCREEN; glConfig.isFullscreen = qtrue; } else { if (noborder) flags |= SDL_NOFRAME; glConfig.isFullscreen = qfalse; } colorbits = r_colorbits->value; if ((!colorbits) || (colorbits >= 32)) colorbits = 24; if (!r_depthbits->value) depthbits = 24; else depthbits = r_depthbits->value; stencilbits = r_stencilbits->value; samples = r_ext_multisample->value; for (i = 0; i < 16; i++) { // 0 - default // 1 - minus colorbits // 2 - minus depthbits // 3 - minus stencil if ((i % 4) == 0 && i) { // one pass, reduce switch (i / 4) { case 2 : if (colorbits == 24) colorbits = 16; break; case 1 : if (depthbits == 24) depthbits = 16; else if (depthbits == 16) depthbits = 8; case 3 : if (stencilbits == 24) stencilbits = 16; else if (stencilbits == 16) stencilbits = 8; } } tcolorbits = colorbits; tdepthbits = depthbits; tstencilbits = stencilbits; if ((i % 4) == 3) { // reduce colorbits if (tcolorbits == 24) tcolorbits = 16; } if ((i % 4) == 2) { // reduce depthbits if (tdepthbits == 24) tdepthbits = 16; else if (tdepthbits == 16) tdepthbits = 8; } if ((i % 4) == 1) { // reduce stencilbits if (tstencilbits == 24) tstencilbits = 16; else if (tstencilbits == 16) tstencilbits = 8; else tstencilbits = 0; } sdlcolorbits = 4; if (tcolorbits == 24) sdlcolorbits = 8; #ifdef __sgi /* Fix for SGIs grabbing too many bits of color */ if (sdlcolorbits == 4) sdlcolorbits = 0; /* Use minimum size for 16-bit color */ /* Need alpha or else SGIs choose 36+ bit RGB mode */ SDL_GL_SetAttribute( SDL_GL_ALPHA_SIZE, 1); #endif SDL_GL_SetAttribute( SDL_GL_RED_SIZE, sdlcolorbits ); SDL_GL_SetAttribute( SDL_GL_GREEN_SIZE, sdlcolorbits ); SDL_GL_SetAttribute( SDL_GL_BLUE_SIZE, sdlcolorbits ); SDL_GL_SetAttribute( SDL_GL_DEPTH_SIZE, tdepthbits ); SDL_GL_SetAttribute( SDL_GL_STENCIL_SIZE, tstencilbits ); SDL_GL_SetAttribute( SDL_GL_MULTISAMPLEBUFFERS, samples ? 1 : 0 ); SDL_GL_SetAttribute( SDL_GL_MULTISAMPLESAMPLES, samples ); if(r_stereoEnabled->integer) { glConfig.stereoEnabled = qtrue; SDL_GL_SetAttribute(SDL_GL_STEREO, 1); } else { glConfig.stereoEnabled = qfalse; SDL_GL_SetAttribute(SDL_GL_STEREO, 0); } SDL_GL_SetAttribute( SDL_GL_DOUBLEBUFFER, 1 ); #if 0 // See http://bugzilla.icculus.org/show_bug.cgi?id=3526 // If not allowing software GL, demand accelerated if( !r_allowSoftwareGL->integer ) { if( SDL_GL_SetAttribute( SDL_GL_ACCELERATED_VISUAL, 1 ) < 0 ) { ri.Printf( PRINT_ALL, "Unable to guarantee accelerated " "visual with libSDL < 1.2.10\n" ); } } #endif if( SDL_GL_SetAttribute( SDL_GL_SWAP_CONTROL, r_swapInterval->integer ) < 0 ) ri.Printf( PRINT_ALL, "r_swapInterval requires libSDL >= 1.2.10\n" ); #ifdef USE_ICON { SDL_Surface *icon = SDL_CreateRGBSurfaceFrom( (void *)CLIENT_WINDOW_ICON.pixel_data, CLIENT_WINDOW_ICON.width, CLIENT_WINDOW_ICON.height, CLIENT_WINDOW_ICON.bytes_per_pixel * 8, CLIENT_WINDOW_ICON.bytes_per_pixel * CLIENT_WINDOW_ICON.width, #ifdef Q3_LITTLE_ENDIAN 0x000000FF, 0x0000FF00, 0x00FF0000, 0xFF000000 #else 0xFF000000, 0x00FF0000, 0x0000FF00, 0x000000FF #endif ); SDL_WM_SetIcon( icon, NULL ); SDL_FreeSurface( icon ); } #endif SDL_WM_SetCaption(CLIENT_WINDOW_TITLE, CLIENT_WINDOW_MIN_TITLE); SDL_ShowCursor(0); if (!(vidscreen = SDL_SetVideoMode(glConfig.vidWidth, glConfig.vidHeight, colorbits, flags))) { ri.Printf( PRINT_DEVELOPER, "SDL_SetVideoMode failed: %s\n", SDL_GetError( ) ); continue; } opengl_context = GLimp_GetCurrentContext(); ri.Printf( PRINT_ALL, "Using %d/%d/%d Color bits, %d depth, %d stencil display.\n", sdlcolorbits, sdlcolorbits, sdlcolorbits, tdepthbits, tstencilbits); glConfig.colorBits = tcolorbits; glConfig.depthBits = tdepthbits; glConfig.stencilBits = tstencilbits; break; } GLimp_DetectAvailableModes(); if (!vidscreen) { ri.Printf( PRINT_ALL, "Couldn't get a visual\n" ); return RSERR_INVALID_MODE; } screen = vidscreen; glstring = (char *) qglGetString (GL_RENDERER); ri.Printf( PRINT_ALL, "GL_RENDERER: %s\n", glstring ); return RSERR_OK; }
/** * @brief Change sv_maxclients and move real clients slots when a demo is playing or stopped */ void SV_DemoChangeMaxClients(void) { int oldMaxClients, oldDemoClients; int i, j, k; client_t *oldClients = NULL; int count; //qboolean firstTime = svs.clients == NULL; // == Checking the prerequisites // Note: we check here that we have enough slots to fit all clients, and that it doesn't overflow the MAX_CLIENTS the engine can support. Also, we save the oldMaxClients and oldDemoClients values. // -- Get the highest client number in use count = 0; for (i = 0 ; i < sv_maxclients->integer ; i++) { if (svs.clients[i].state >= CS_CONNECTED) { if (i > count) { count = i; } } } count++; // -- Save the previous oldMaxClients and oldDemoClients values, and update // Save the previous sv_maxclients value before updating it oldMaxClients = sv_maxclients->integer; // update the cvars Cvar_Get("sv_maxclients", "8", 0); Cvar_Get("sv_democlients", "0", 0); // unnecessary now that sv_democlients is not latched anymore? // Save the previous sv_democlients (since it's updated instantly, we cannot get it directly), we use a trick by computing the difference between the new and previous sv_maxclients (the difference should indeed be the exact value of sv_democlients) oldDemoClients = (oldMaxClients - sv_maxclients->integer); if (oldDemoClients < 0) // if the difference is negative, this means that before it was set to 0 (because the newer sv_maxclients is greater than the old) { oldDemoClients = 0; } // -- Check limits // never go below the highest client number in use (make sure we have enough room for all players) SV_BoundMaxClients(count); // -- Change check: if still the same, we just quit, there's nothing to do if (sv_maxclients->integer == oldMaxClients) { return; } // == Memorizing clients // Note: we save in a temporary variables the clients, because after we will wipe completely the svs.clients struct // copy the clients to hunk memory oldClients = Hunk_AllocateTempMemory((sv_maxclients->integer - sv_democlients->integer) * sizeof(client_t)); // we allocate just enough memory for the real clients (not counting in the democlients) // For all previous clients slots, we copy the entire client into a temporary var for (i = 0, j = 0, k = sv_privateClients->integer ; i < oldMaxClients ; i++) // for all the previously connected clients, we copy them to a temporary var { // If there is a real client in this slot if (svs.clients[i].state >= CS_CONNECTED) { // if the client is in a privateClient reserved slot, we move him on the reserved slots if (i >= oldDemoClients && i < oldDemoClients + sv_privateClients->integer) { oldClients[j++] = svs.clients[i]; // else the client is not a privateClient, and we move him to the first available slot after the privateClients slots } else { oldClients[k++] = svs.clients[i]; } } } // Fill in the remaining clients slots with empty clients (else the engine crash when copying into memory svs.clients) for (i = j; i < sv_privateClients->integer; i++) // Fill the privateClients empty slots { Com_Memset(&oldClients[i], 0, sizeof(client_t)); } for (i = k; i < (sv_maxclients->integer - sv_democlients->integer); i++) // Fill the other normal clients slots { Com_Memset(&oldClients[i], 0, sizeof(client_t)); } // free old clients arrays Z_Free(svs.clients); // == Allocating the new svs.clients and moving the saved clients over from the temporary var // allocate new svs.clients svs.clients = Z_Malloc(sv_maxclients->integer * sizeof(client_t)); Com_Memset(svs.clients, 0, sv_maxclients->integer * sizeof(client_t)); // copy the clients over (and move them depending on sv_democlients: if >0, move them upwards, if == 0, move them to their original slots) Com_Memcpy(svs.clients + sv_democlients->integer, oldClients, (sv_maxclients->integer - sv_democlients->integer) * sizeof(client_t)); // free the old clients on the hunk Hunk_FreeTempMemory(oldClients); // == Allocating snapshot entities // allocate new snapshot entities if (com_dedicated->integer) { svs.numSnapshotEntities = sv_maxclients->integer * PACKET_BACKUP * 64; } else { // we don't need nearly as many when playing locally svs.numSnapshotEntities = sv_maxclients->integer * 4 * 64; } // == Server-side demos management // set demostate to none if it was just waiting to set maxclients and move real clients slots if (sv.demoState == DS_WAITINGSTOP) { sv.demoState = DS_NONE; Cvar_SetValue("sv_demoState", DS_NONE); } }
/* ================== CM_PatchCollideFromGrid ================== */ static void CM_SurfaceCollideFromGrid(cGrid_t * grid, cSurfaceCollide_t * sc) { int i, j, gridPlanes[MAX_GRID_SIZE][MAX_GRID_SIZE][2], borders[4], noAdjust[4]; float *p1, *p2, *p3; cFacet_t *facet; numPlanes = 0; numFacets = 0; // find the planes for each triangle of the grid for(i = 0; i < grid->width - 1; i++) { for(j = 0; j < grid->height - 1; j++) { p1 = grid->points[i][j]; p2 = grid->points[i + 1][j]; p3 = grid->points[i + 1][j + 1]; gridPlanes[i][j][0] = CM_FindPlane(p1, p2, p3); p1 = grid->points[i + 1][j + 1]; p2 = grid->points[i][j + 1]; p3 = grid->points[i][j]; gridPlanes[i][j][1] = CM_FindPlane(p1, p2, p3); } } // create the borders for each facet for(i = 0; i < grid->width - 1; i++) { for(j = 0; j < grid->height - 1; j++) { borders[EN_TOP] = -1; if(j > 0) { borders[EN_TOP] = gridPlanes[i][j - 1][1]; } else if(grid->wrapHeight) { borders[EN_TOP] = gridPlanes[i][grid->height - 2][1]; } noAdjust[EN_TOP] = (borders[EN_TOP] == gridPlanes[i][j][0]); if(borders[EN_TOP] == -1 || noAdjust[EN_TOP]) { borders[EN_TOP] = CM_EdgePlaneNum(grid, gridPlanes, i, j, 0); } borders[EN_BOTTOM] = -1; if(j < grid->height - 2) { borders[EN_BOTTOM] = gridPlanes[i][j + 1][0]; } else if(grid->wrapHeight) { borders[EN_BOTTOM] = gridPlanes[i][0][0]; } noAdjust[EN_BOTTOM] = (borders[EN_BOTTOM] == gridPlanes[i][j][1]); if(borders[EN_BOTTOM] == -1 || noAdjust[EN_BOTTOM]) { borders[EN_BOTTOM] = CM_EdgePlaneNum(grid, gridPlanes, i, j, 2); } borders[EN_LEFT] = -1; if(i > 0) { borders[EN_LEFT] = gridPlanes[i - 1][j][0]; } else if(grid->wrapWidth) { borders[EN_LEFT] = gridPlanes[grid->width - 2][j][0]; } noAdjust[EN_LEFT] = (borders[EN_LEFT] == gridPlanes[i][j][1]); if(borders[EN_LEFT] == -1 || noAdjust[EN_LEFT]) { borders[EN_LEFT] = CM_EdgePlaneNum(grid, gridPlanes, i, j, 3); } borders[EN_RIGHT] = -1; if(i < grid->width - 2) { borders[EN_RIGHT] = gridPlanes[i + 1][j][1]; } else if(grid->wrapWidth) { borders[EN_RIGHT] = gridPlanes[0][j][1]; } noAdjust[EN_RIGHT] = (borders[EN_RIGHT] == gridPlanes[i][j][0]); if(borders[EN_RIGHT] == -1 || noAdjust[EN_RIGHT]) { borders[EN_RIGHT] = CM_EdgePlaneNum(grid, gridPlanes, i, j, 1); } if(numFacets == MAX_FACETS) { Com_Error(ERR_DROP, "MAX_FACETS"); } facet = &facets[numFacets]; Com_Memset(facet, 0, sizeof(*facet)); if(gridPlanes[i][j][0] == gridPlanes[i][j][1]) { if(gridPlanes[i][j][0] == -1) { continue; // degenrate } facet->surfacePlane = gridPlanes[i][j][0]; facet->numBorders = 4; facet->borderPlanes[0] = borders[EN_TOP]; facet->borderNoAdjust[0] = (qboolean)noAdjust[EN_TOP]; facet->borderPlanes[1] = borders[EN_RIGHT]; facet->borderNoAdjust[1] = (qboolean)noAdjust[EN_RIGHT]; facet->borderPlanes[2] = borders[EN_BOTTOM]; facet->borderNoAdjust[2] = (qboolean)noAdjust[EN_BOTTOM]; facet->borderPlanes[3] = borders[EN_LEFT]; facet->borderNoAdjust[3] = (qboolean)noAdjust[EN_LEFT]; CM_SetBorderInward(facet, grid, gridPlanes, i, j, -1); if(CM_ValidateFacet(facet)) { CM_AddFacetBevels(facet); numFacets++; } } else { // two seperate triangles facet->surfacePlane = gridPlanes[i][j][0]; facet->numBorders = 3; facet->borderPlanes[0] = borders[EN_TOP]; facet->borderNoAdjust[0] = (qboolean)noAdjust[EN_TOP]; facet->borderPlanes[1] = borders[EN_RIGHT]; facet->borderNoAdjust[1] = (qboolean)noAdjust[EN_RIGHT]; facet->borderPlanes[2] = gridPlanes[i][j][1]; if(facet->borderPlanes[2] == -1) { facet->borderPlanes[2] = borders[EN_BOTTOM]; if(facet->borderPlanes[2] == -1) { facet->borderPlanes[2] = CM_EdgePlaneNum(grid, gridPlanes, i, j, 4); } } CM_SetBorderInward(facet, grid, gridPlanes, i, j, 0); if(CM_ValidateFacet(facet)) { CM_AddFacetBevels(facet); numFacets++; } if(numFacets == MAX_FACETS) { Com_Error(ERR_DROP, "MAX_FACETS"); } facet = &facets[numFacets]; Com_Memset(facet, 0, sizeof(*facet)); facet->surfacePlane = gridPlanes[i][j][1]; facet->numBorders = 3; facet->borderPlanes[0] = borders[EN_BOTTOM]; facet->borderNoAdjust[0] = (qboolean)noAdjust[EN_BOTTOM]; facet->borderPlanes[1] = borders[EN_LEFT]; facet->borderNoAdjust[1] = (qboolean)noAdjust[EN_LEFT]; facet->borderPlanes[2] = gridPlanes[i][j][0]; if(facet->borderPlanes[2] == -1) { facet->borderPlanes[2] = borders[EN_TOP]; if(facet->borderPlanes[2] == -1) { facet->borderPlanes[2] = CM_EdgePlaneNum(grid, gridPlanes, i, j, 5); } } CM_SetBorderInward(facet, grid, gridPlanes, i, j, 1); if(CM_ValidateFacet(facet)) { CM_AddFacetBevels(facet); numFacets++; } } } } // copy the results out sc->numPlanes = numPlanes; sc->numFacets = numFacets; sc->facets = (cFacet_t*)Hunk_Alloc(numFacets * sizeof(*sc->facets), h_high); Com_Memcpy(sc->facets, facets, numFacets * sizeof(*sc->facets)); sc->planes = (cPlane_t*)Hunk_Alloc(numPlanes * sizeof(*sc->planes), h_high); Com_Memcpy(sc->planes, planes, numPlanes * sizeof(*sc->planes)); }
/* ==================== CL_CgameSystemCalls The cgame module is making a system call ==================== */ intptr_t CL_CgameSystemCalls(intptr_t * args) { switch (args[0]) { case CG_PRINT: Com_Printf("%s", (const char *)VMA(1)); return 0; case CG_ERROR: Com_Error(ERR_DROP, "%s", (const char *)VMA(1)); return 0; case CG_MILLISECONDS: return Sys_Milliseconds(); case CG_CVAR_REGISTER: Cvar_Register(VMA(1), VMA(2), VMA(3), args[4]); return 0; case CG_CVAR_UPDATE: Cvar_Update(VMA(1)); return 0; case CG_CVAR_SET: Cvar_Set(VMA(1), VMA(2)); return 0; case CG_CVAR_VARIABLESTRINGBUFFER: Cvar_VariableStringBuffer(VMA(1), VMA(2), args[3]); return 0; case CG_ARGC: return Cmd_Argc(); case CG_ARGV: Cmd_ArgvBuffer(args[1], VMA(2), args[3]); return 0; case CG_ARGS: Cmd_ArgsBuffer(VMA(1), args[2]); return 0; case CG_FS_FOPENFILE: return FS_FOpenFileByMode(VMA(1), VMA(2), args[3]); case CG_FS_READ: FS_Read2(VMA(1), args[2], args[3]); return 0; case CG_FS_WRITE: FS_Write(VMA(1), args[2], args[3]); return 0; case CG_FS_FCLOSEFILE: FS_FCloseFile(args[1]); return 0; case CG_FS_SEEK: return FS_Seek(args[1], args[2], args[3]); case CG_FS_GETFILELIST: return FS_GetFileList(VMA(1), VMA(2), VMA(3), args[4]); case CG_SENDCONSOLECOMMAND: Cbuf_AddText(VMA(1)); return 0; case CG_ADDCOMMAND: CL_AddCgameCommand(VMA(1)); return 0; case CG_REMOVECOMMAND: Cmd_RemoveCommand(VMA(1)); return 0; case CG_SENDCLIENTCOMMAND: CL_AddReliableCommand(VMA(1), qfalse); return 0; case CG_UPDATESCREEN: // this is used during lengthy level loading, so pump message loop // We can't call Com_EventLoop here, a restart will crash and this _does_ happen // if there is a map change while we are downloading at pk3. ZOID SCR_UpdateScreen(); return 0; case CG_CM_LOADMAP: CL_CM_LoadMap(VMA(1)); return 0; case CG_CM_NUMINLINEMODELS: return CM_NumInlineModels(); case CG_CM_INLINEMODEL: return CM_InlineModel(args[1]); case CG_CM_TEMPBOXMODEL: return CM_TempBoxModel(VMA(1), VMA(2), /*int capsule */ qfalse); case CG_CM_TEMPCAPSULEMODEL: return CM_TempBoxModel(VMA(1), VMA(2), /*int capsule */ qtrue); case CG_CM_POINTCONTENTS: return CM_PointContents(VMA(1), args[2]); case CG_CM_TRANSFORMEDPOINTCONTENTS: return CM_TransformedPointContents(VMA(1), args[2], VMA(3), VMA(4)); case CG_CM_BOXTRACE: CM_BoxTrace(VMA(1), VMA(2), VMA(3), VMA(4), VMA(5), args[6], args[7], TT_AABB); return 0; case CG_CM_CAPSULETRACE: CM_BoxTrace(VMA(1), VMA(2), VMA(3), VMA(4), VMA(5), args[6], args[7], TT_CAPSULE); return 0; case CG_CM_TRANSFORMEDBOXTRACE: CM_TransformedBoxTrace(VMA(1), VMA(2), VMA(3), VMA(4), VMA(5), args[6], args[7], VMA(8), VMA(9), TT_AABB); return 0; case CG_CM_TRANSFORMEDCAPSULETRACE: CM_TransformedBoxTrace(VMA(1), VMA(2), VMA(3), VMA(4), VMA(5), args[6], args[7], VMA(8), VMA(9), TT_CAPSULE); return 0; case CG_CM_BISPHERETRACE: CM_BiSphereTrace(VMA(1), VMA(2), VMA(3), VMF(4), VMF(5), args[6], args[7]); return 0; case CG_CM_TRANSFORMEDBISPHERETRACE: CM_TransformedBiSphereTrace(VMA(1), VMA(2), VMA(3), VMF(4), VMF(5), args[6], args[7], VMA(8)); return 0; case CG_CM_MARKFRAGMENTS: return re.MarkFragments(args[1], VMA(2), VMA(3), args[4], VMA(5), args[6], VMA(7)); case CG_S_STARTSOUND: S_StartSound(VMA(1), args[2], args[3], args[4]); return 0; case CG_S_STARTLOCALSOUND: S_StartLocalSound(args[1], args[2]); return 0; case CG_S_CLEARLOOPINGSOUNDS: S_ClearLoopingSounds(args[1]); return 0; case CG_S_ADDLOOPINGSOUND: S_AddLoopingSound(args[1], VMA(2), VMA(3), args[4]); return 0; case CG_S_ADDREALLOOPINGSOUND: S_AddRealLoopingSound(args[1], VMA(2), VMA(3), args[4]); return 0; case CG_S_STOPLOOPINGSOUND: S_StopLoopingSound(args[1]); return 0; case CG_S_UPDATEENTITYPOSITION: S_UpdateEntityPosition(args[1], VMA(2)); return 0; case CG_S_RESPATIALIZE: S_Respatialize(args[1], VMA(2), VMA(3), args[4]); return 0; case CG_S_REGISTERSOUND: return S_RegisterSound(VMA(1)); case CG_S_STARTBACKGROUNDTRACK: S_StartBackgroundTrack(VMA(1), VMA(2)); return 0; case CG_R_LOADWORLDMAP: re.LoadWorld(VMA(1)); return 0; case CG_R_REGISTERMODEL: return re.RegisterModel(VMA(1), args[2]); case CG_R_REGISTERANIMATION: return re.RegisterAnimation(VMA(1)); case CG_R_REGISTERSKIN: return re.RegisterSkin(VMA(1)); case CG_R_REGISTERSHADER: return re.RegisterShader(VMA(1)); case CG_R_REGISTERSHADERNOMIP: return re.RegisterShaderNoMip(VMA(1)); case CG_R_REGISTERSHADERLIGHTATTENUATION: return re.RegisterShaderLightAttenuation(VMA(1)); case CG_R_REGISTERFONT: re.RegisterFont(VMA(1), args[2], VMA(3)); case CG_R_CLEARSCENE: re.ClearScene(); return 0; case CG_R_ADDREFENTITYTOSCENE: re.AddRefEntityToScene(VMA(1)); return 0; case CG_R_ADDREFLIGHTSTOSCENE: re.AddRefLightToScene(VMA(1)); return 0; case CG_R_ADDPOLYTOSCENE: re.AddPolyToScene(args[1], args[2], VMA(3), 1); return 0; case CG_R_ADDPOLYSTOSCENE: re.AddPolyToScene(args[1], args[2], VMA(3), args[4]); return 0; case CG_R_LIGHTFORPOINT: return re.LightForPoint(VMA(1), VMA(2), VMA(3), VMA(4)); case CG_R_ADDLIGHTTOSCENE: re.AddLightToScene(VMA(1), VMF(2), VMF(3), VMF(4), VMF(5)); return 0; case CG_R_RENDERSCENE: re.RenderScene(VMA(1)); return 0; case CG_R_SETCOLOR: re.SetColor(VMA(1)); return 0; case CG_R_DRAWSTRETCHPIC: re.DrawStretchPic(VMF(1), VMF(2), VMF(3), VMF(4), VMF(5), VMF(6), VMF(7), VMF(8), args[9]); return 0; case CG_R_MODELBOUNDS: re.ModelBounds(args[1], VMA(2), VMA(3)); return 0; case CG_R_LERPTAG: return re.LerpTag(VMA(1), args[2], args[3], args[4], VMF(5), VMA(6)); case CG_R_CHECKSKELETON: return re.CheckSkeleton(VMA(1), args[2], args[3]); case CG_R_BUILDSKELETON: return re.BuildSkeleton(VMA(1), args[2], args[3], args[4], VMF(5), args[6]); case CG_R_BLENDSKELETON: return re.BlendSkeleton(VMA(1), VMA(2), VMF(3)); case CG_R_BONEINDEX: return re.BoneIndex(args[1], VMA(2)); case CG_R_ANIMNUMFRAMES: return re.AnimNumFrames(args[1]); case CG_R_ANIMFRAMERATE: return re.AnimFrameRate(args[1]); case CG_GETGLCONFIG: CL_GetGlconfig(VMA(1)); return 0; case CG_GETGAMESTATE: CL_GetGameState(VMA(1)); return 0; case CG_GETCURRENTSNAPSHOTNUMBER: CL_GetCurrentSnapshotNumber(VMA(1), VMA(2)); return 0; case CG_GETSNAPSHOT: return CL_GetSnapshot(args[1], VMA(2)); case CG_GETSERVERCOMMAND: return CL_GetServerCommand(args[1]); case CG_GETCURRENTCMDNUMBER: return CL_GetCurrentCmdNumber(); case CG_GETUSERCMD: return CL_GetUserCmd(args[1], VMA(2)); case CG_SETUSERCMDVALUE: CL_SetUserCmdValue(args[1], VMF(2)); return 0; case CG_MEMORY_REMAINING: return Hunk_MemoryRemaining(); case CG_KEY_ISDOWN: return Key_IsDown(args[1]); case CG_KEY_GETCATCHER: return Key_GetCatcher(); case CG_KEY_SETCATCHER: // Don't allow the cgame module to close the console Key_SetCatcher(args[1] | (Key_GetCatcher() & KEYCATCH_CONSOLE)); return 0; case CG_KEY_GETKEY: return Key_GetKey(VMA(1)); case CG_GETDEMOSTATE: return CL_DemoState(); case CG_GETDEMOPOS: return CL_DemoPos(); case CG_GETDEMONAME: CL_DemoName(VMA(1), args[2]); return 0; case CG_KEY_KEYNUMTOSTRINGBUF: Key_KeynumToStringBuf(args[1], VMA(2), args[3]); return 0; case CG_KEY_GETBINDINGBUF: Key_GetBindingBuf(args[1], VMA(2), args[3]); return 0; case CG_KEY_SETBINDING: Key_SetBinding(args[1], VMA(2)); return 0; case CG_PC_ADD_GLOBAL_DEFINE: return Parse_AddGlobalDefine(VMA(1)); case CG_PC_LOAD_SOURCE: return Parse_LoadSourceHandle(VMA(1)); case CG_PC_FREE_SOURCE: return Parse_FreeSourceHandle(args[1]); case CG_PC_READ_TOKEN: return Parse_ReadTokenHandle(args[1], VMA(2)); case CG_PC_SOURCE_FILE_AND_LINE: return Parse_SourceFileAndLine(args[1], VMA(2), VMA(3)); case CG_MEMSET: Com_Memset(VMA(1), args[2], args[3]); return 0; case CG_MEMCPY: Com_Memcpy(VMA(1), VMA(2), args[3]); return 0; case CG_STRNCPY: strncpy(VMA(1), VMA(2), args[3]); return args[1]; case CG_SIN: return FloatAsInt(sin(VMF(1))); case CG_COS: return FloatAsInt(cos(VMF(1))); case CG_ATAN2: return FloatAsInt(atan2(VMF(1), VMF(2))); case CG_SQRT: return FloatAsInt(sqrt(VMF(1))); case CG_FLOOR: return FloatAsInt(floor(VMF(1))); case CG_CEIL: return FloatAsInt(ceil(VMF(1))); case CG_ACOS: return FloatAsInt(Q_acos(VMF(1))); case CG_S_STOPBACKGROUNDTRACK: S_StopBackgroundTrack(); return 0; case CG_REAL_TIME: return Com_RealTime(VMA(1)); case CG_CIN_PLAYCINEMATIC: return CIN_PlayCinematic(VMA(1), args[2], args[3], args[4], args[5], args[6]); case CG_CIN_STOPCINEMATIC: return CIN_StopCinematic(args[1]); case CG_CIN_RUNCINEMATIC: return CIN_RunCinematic(args[1]); case CG_CIN_DRAWCINEMATIC: CIN_DrawCinematic(args[1]); return 0; case CG_CIN_SETEXTENTS: CIN_SetExtents(args[1], args[2], args[3], args[4], args[5]); return 0; case CG_R_REMAP_SHADER: re.RemapShader(VMA(1), VMA(2), VMA(3)); return 0; /* case CG_LOADCAMERA: return loadCamera(VMA(1)); case CG_STARTCAMERA: startCamera(args[1]); return 0; case CG_GETCAMERAINFO: return getCameraInfo(args[1], VMA(2), VMA(3)); */ case CG_GET_ENTITY_TOKEN: return re.GetEntityToken(VMA(1), args[2]); case CG_R_INPVS: return re.inPVS(VMA(1), VMA(2)); // Rogue Reborn case CG_LOAD_WEAPON: return JS_LoadWeapon(args[1], VMA(2)); case CG_GET_WEAPON_ATTRIBUTES: return JS_GetWeaponAttributes(args[1], args[2], (const void **)(args[3])); default: assert(0); Com_Error(ERR_DROP, "Bad cgame system trap: %ld", (long int)args[0]); } return 0; }
/* ================ Con_CheckResize If the line width has changed, reformat the buffer. ================ */ qboolean Con_CheckResize( void ) { int i, textWidthInChars, oldwidth, oldtotallines, numlines, numchars; conChar_t buf[ CON_TEXTSIZE ]; qboolean ret = qtrue; if ( cls.glconfig.vidWidth ) { const int consoleVidWidth = cls.glconfig.vidWidth - 2 * (consoleState.margin.sides + consoleState.padding.sides ); textWidthInChars = consoleVidWidth / SCR_ConsoleFontUnicharWidth( 'W' ); } else { textWidthInChars = 0; } if ( textWidthInChars == consoleState.textWidthInChars ) { // nothing } else if ( textWidthInChars < 1 ) // video hasn't been initialized yet { consoleState.textWidthInChars = DEFAULT_CONSOLE_WIDTH; consoleState.maxScrollbackLengthInLines = CON_TEXTSIZE / consoleState.textWidthInChars; Con_Clear(); consoleState.currentLine = consoleState.maxScrollbackLengthInLines - 1; consoleState.bottomDisplayedLine = consoleState.currentLine; consoleState.scrollLineIndex = consoleState.currentLine; ret = qfalse; } else { oldwidth = consoleState.textWidthInChars; consoleState.textWidthInChars = textWidthInChars; oldtotallines = consoleState.maxScrollbackLengthInLines; consoleState.maxScrollbackLengthInLines = CON_TEXTSIZE / consoleState.textWidthInChars; numlines = oldwidth < 0 ? 0 : oldtotallines; if ( consoleState.maxScrollbackLengthInLines < numlines ) { numlines = consoleState.maxScrollbackLengthInLines; } numchars = oldwidth; if ( consoleState.textWidthInChars < numchars ) { numchars = consoleState.textWidthInChars; } Com_Memcpy( buf, consoleState.text, sizeof( consoleState.text ) ); Con_Clear(); for ( i = 0; i < numlines; i++ ) { conChar_t* destination = consoleState.text + ( consoleState.maxScrollbackLengthInLines - 1 - i ) * consoleState.textWidthInChars; memcpy( destination, buf + ( ( consoleState.currentLine - i + oldtotallines ) % oldtotallines ) * oldwidth, numchars * sizeof( conChar_t ) ); if( destination[0].ch ) consoleState.usedScrollbackLengthInLines++; } consoleState.currentLine = consoleState.maxScrollbackLengthInLines - 1; consoleState.bottomDisplayedLine = consoleState.currentLine; consoleState.scrollLineIndex = consoleState.currentLine; } if ( con_prompt ) { char prompt[ MAX_STRING_CHARS ]; Q_strncpyz( prompt, con_prompt->string, sizeof( prompt ) ); Q_CleanStr( prompt ); g_console_field_width = consoleState.textWidthInChars - 8 - Q_UTF8_Strlen( prompt ); g_consoleField.SetWidth(g_console_field_width); } return ret; }