/* * Con_DrawInput * * The input line scrolls horizontally if typing goes beyond the right edge */ static void Con_DrawInput( int vislines ) { char draw_search_text[MAXCMDLINE*2+4]; const char *text = key_lines[edit_line]; int smallCharHeight = SCR_strHeight( cls.fontSystemSmall ); int text_y = vislines - 14 - smallCharHeight; const int left_margin = 8, right_margin = 8; int promptwidth = SCR_strWidth( "]", cls.fontSystemSmall, 1 ); int cursorwidth = SCR_strWidth( "_", cls.fontSystemSmall, 1 ); int input_width = viddef.width - left_margin - right_margin; int prewidth; // width of input line before cursor if( cls.key_dest != key_console ) return; if( search_text[0] ) { text = draw_search_text; Q_snprintfz( draw_search_text, sizeof( draw_search_text ), "%s : %s", key_lines[edit_line], search_text ); } prewidth = SCR_strWidth( text, cls.fontSystemSmall, key_linepos ); // don't let the cursor go beyond the left screen edge clamp_high( input_prestep, prewidth - promptwidth); // don't let it go beyond the right screen edge clamp_low( input_prestep, prewidth - ( input_width - cursorwidth ) ); SCR_DrawClampString( left_margin - input_prestep, text_y, text, left_margin, text_y, viddef.width - right_margin, viddef.height, cls.fontSystemSmall, colorWhite ); if( (int)( cls.realtime>>8 )&1 ) SCR_DrawRawChar( left_margin + prewidth - input_prestep, text_y, '_', cls.fontSystemSmall, colorWhite ); }
/* * source_setup */ static void source_setup( src_t *src, sfx_t *sfx, int priority, int entNum, int channel, float fvol, float attenuation ) { ALuint buffer; // Mark the SFX as used, and grab the raw AL buffer S_UseBuffer( sfx ); buffer = S_GetALBuffer( sfx ); clamp_low( attenuation, 0.0f ); src->lastUse = trap_Milliseconds(); src->sfx = sfx; src->priority = priority; src->entNum = entNum; src->channel = channel; src->fvol = fvol; src->attenuation = attenuation; src->isActive = qtrue; src->isLocked = qfalse; src->isLooping = qfalse; src->isTracking = qfalse; VectorClear( src->origin ); VectorClear( src->velocity ); qalSourcefv( src->source, AL_POSITION, vec3_origin ); qalSourcefv( src->source, AL_VELOCITY, vec3_origin ); qalSourcef( src->source, AL_GAIN, fvol * s_volume->value ); qalSourcei( src->source, AL_SOURCE_RELATIVE, AL_FALSE ); qalSourcei( src->source, AL_LOOPING, AL_FALSE ); qalSourcei( src->source, AL_BUFFER, buffer ); qalSourcef( src->source, AL_REFERENCE_DISTANCE, s_attenuation_refdistance ); qalSourcef( src->source, AL_MAX_DISTANCE, s_attenuation_maxdistance ); qalSourcef( src->source, AL_ROLLOFF_FACTOR, attenuation ); }
void objectString_Release( asstring_t *obj ) { obj->asRefCount--; clamp_low( obj->asRefCount, 0 ); if( !obj->asRefCount ) { QAS_Free( obj->buffer ); QAS_Free( obj ); } }
/* * SCR_DrawClampFillRect * * Fills a scissored box of pixels with a single color */ void SCR_DrawClampFillRect( int x, int y, int w, int h, int xmin, int ymin, int xmax, int ymax, vec4_t color ) { int x2 = x + w; int y2 = y + h; if( ( xmax <= xmin ) || ( ymax <= ymin ) ) return; clamp_low( x, xmin ); clamp_low( y, ymin ); clamp_high( x2, xmax ); clamp_high( y2, ymax ); w = x2 - x; h = y2 - y; if( ( w <= 0 ) || ( h <= 0 ) ) return; re.DrawStretchPic( x, y, w, h, 0, 0, 1, 1, color, cls.whiteShader ); }
void objectString_Release( asstring_t *obj ) { obj->asRefCount--; clamp_low( obj->asRefCount, 0 ); if( !obj->asRefCount ) { if( ( obj->size & CONST_STRING_BITFLAG ) == 0 ) { delete[] obj->buffer; delete obj; } else { qbyte *rawmem = ( qbyte * )obj; delete[] rawmem; } } }
void RF_BeginFrame( float cameraSeparation, bool forceClear, bool forceVsync, bool uncappedFPS ) { int swapInterval; RF_CheckCvars(); // run cinematic passes on shaders R_RunAllCinematics(); if( uncappedFPS ) { rrf.adapter.maxfps = 0; } else { rrf.adapter.maxfps = r_maxfps->integer; } // take the frame the backend is not busy processing if( glConfig.multithreading ) { ri.Mutex_Lock( rrf.adapter.frameLock ); if( rrf.lastFrameNum == rrf.adapter.frameNum ) rrf.frameNum = (rrf.adapter.frameNum + 1) % 3; else rrf.frameNum = 3 - (rrf.adapter.frameNum + rrf.lastFrameNum); if( rrf.frameNum == 3 ) { rrf.frameNum = 1; } rrf.frame = rrf.frames[rrf.frameNum]; ri.Mutex_Unlock( rrf.adapter.frameLock ); } rrf.frame->Clear( rrf.frame ); rrf.cameraSeparation = cameraSeparation; R_DataSync(); swapInterval = r_swapinterval->integer || forceVsync ? 1 : 0; clamp_low( swapInterval, r_swapinterval_min->integer ); rrf.frame->BeginFrame( rrf.frame, cameraSeparation, forceClear, swapInterval ); }
void G_Items_RespawnByType( unsigned int typeMask, int item_tag, float delay ) { edict_t *ent; int msecs; for( ent = game.edicts + gs.maxclients + BODY_QUEUE_SIZE; ENTNUM( ent ) < game.maxentities; ent++ ) { if( !ent->r.inuse || !ent->item ) continue; if( typeMask && !( ent->item->type & typeMask ) ) continue; if( ent->spawnflags & ( DROPPED_ITEM|DROPPED_PLAYER_ITEM ) ) { G_FreeEdict( ent ); continue; } if( !G_Gametype_CanRespawnItem( ent->item ) ) continue; // if a tag is specified, ignore others of the same type if( item_tag > 0 && ( ent->item->tag != item_tag ) ) continue; msecs = (int)( delay * 1000 ); if( msecs >= 0 ) clamp_low( msecs, 1 ); // megahealth is different if( ( ent->style & HEALTH_TIMED ) && ent->r.owner ) ent->r.owner = NULL; SetRespawn( ent, msecs ); } }
//========================================== // AI_PickShortRangeGoal // Pick best goal based on importance and range. This function // overrides the long range goal selection for items that // are very close to the bot and are reachable. //========================================== static void AI_PickShortRangeGoal( edict_t *self ) { edict_t *bestGoal = NULL; float bestWeight = 0; nav_ents_t *goalEnt; const gsitem_t *item; bool canPickupItems; int i; if( !self->r.client || G_ISGHOSTING( self ) ) return; if( self->ai->state_combat_timeout > level.time ) { self->ai->shortRangeGoalTimeout = self->ai->state_combat_timeout; return; } if( self->ai->shortRangeGoalTimeout > level.time ) return; canPickupItems = (self->r.client->ps.pmove.stats[PM_STAT_FEATURES] & PMFEAT_ITEMPICK) != 0 ? true : false; self->ai->shortRangeGoalTimeout = level.time + AI_SHORT_RANGE_GOAL_DELAY; self->movetarget = NULL; FOREACH_GOALENT( goalEnt ) { float dist; i = goalEnt->id; if( !goalEnt->ent->r.inuse || goalEnt->ent->r.solid == SOLID_NOT ) continue; if( goalEnt->ent->r.client ) continue; if( self->ai->status.entityWeights[i] <= 0.0f ) continue; item = goalEnt->ent->item; if( canPickupItems && item ) { if( !G_Gametype_CanPickUpItem( item ) || !( item->flags & ITFLAG_PICKABLE ) ) { continue; } } dist = DistanceFast( self->s.origin, goalEnt->ent->s.origin ); if( goalEnt == self->ai->goalEnt ) { if( dist > AI_GOAL_SR_LR_RADIUS ) continue; } else { if( dist > AI_GOAL_SR_RADIUS ) continue; } clamp_low( dist, 0.01f ); if( AI_ShortRangeReachable( self, goalEnt->ent->s.origin ) ) { float weight; bool in_front = G_InFront( self, goalEnt->ent ); // Long range goal gets top priority if( in_front && goalEnt == self->ai->goalEnt ) { bestGoal = goalEnt->ent; break; } // get the one with the best weight weight = self->ai->status.entityWeights[i] / dist * (in_front ? 1.0f : 0.5f); if( weight > bestWeight ) { bestWeight = weight; bestGoal = goalEnt->ent; } } } if( bestGoal ) { self->movetarget = bestGoal; if( nav.debugMode && bot_showsrgoal->integer ) G_PrintChasersf( self, "%i %s: selected a %s for SR goal.\n", level.framenum, self->ai->pers.netname, self->movetarget->classname ); } else { // got nothing else to do so keep scanning self->ai->shortRangeGoalTimeout = level.time + AI_SHORT_RANGE_GOAL_DELAY_IDLE; } }
//========================================== // AI_PickLongRangeGoal // // Evaluate the best long range goal and send the bot on // its way. This is a good time waster, so use it sparingly. // Do not call it for every think cycle. // // jal: I don't think there is any problem by calling it, // now that we have stored the costs at the nav.costs table (I don't do it anyway) //========================================== void AI_PickLongRangeGoal( edict_t *self ) { #define WEIGHT_MAXDISTANCE_FACTOR 20000.0f #define COST_INFLUENCE 0.5f int i; float weight, bestWeight = 0.0; int current_node; float cost; float dist; nav_ents_t *goalEnt, *bestGoalEnt = NULL; AI_ClearGoal( self ); if( G_ISGHOSTING( self ) ) return; if( self->ai->longRangeGoalTimeout > level.time ) return; if( !self->r.client->ps.pmove.stats[PM_STAT_MAXSPEED] ) { return; } self->ai->longRangeGoalTimeout = level.time + AI_LONG_RANGE_GOAL_DELAY + brandom( 0, 1000 ); // look for a target current_node = AI_FindClosestReachableNode( self->s.origin, self, ( ( 1 + self->ai->nearest_node_tries ) * NODE_DENSITY ), NODE_ALL ); self->ai->current_node = current_node; if( current_node == NODE_INVALID ) { if( nav.debugMode && bot_showlrgoal->integer ) G_PrintChasersf( self, "%s: LRGOAL: Closest node not found. Tries:%i\n", self->ai->pers.netname, self->ai->nearest_node_tries ); self->ai->nearest_node_tries++; // extend search radius with each try return; } self->ai->nearest_node_tries = 0; // Run the list of potential goal entities FOREACH_GOALENT( goalEnt ) { i = goalEnt->id; if( !goalEnt->ent ) continue; if( !goalEnt->ent->r.inuse ) { goalEnt->node = NODE_INVALID; continue; } if( goalEnt->ent->r.client ) { if( G_ISGHOSTING( goalEnt->ent ) || goalEnt->ent->flags & (FL_NOTARGET|FL_BUSY) ) goalEnt->node = NODE_INVALID; else goalEnt->node = AI_FindClosestReachableNode( goalEnt->ent->s.origin, goalEnt->ent, NODE_DENSITY, NODE_ALL ); } if( goalEnt->ent->item ) { if( !G_Gametype_CanPickUpItem( goalEnt->ent->item ) ) continue; } if( goalEnt->node == NODE_INVALID ) continue; weight = self->ai->status.entityWeights[i]; if( weight <= 0.0f ) continue; // don't try to find cost for too far away objects dist = DistanceFast( self->s.origin, goalEnt->ent->s.origin ); if( dist > WEIGHT_MAXDISTANCE_FACTOR * weight/* || dist < AI_GOAL_SR_RADIUS*/ ) continue; cost = AI_FindCost( current_node, goalEnt->node, self->ai->status.moveTypesMask ); if( cost == NODE_INVALID ) continue; cost -= brandom( 0, 2000 ); // allow random variations clamp_low( cost, 1 ); weight = ( 1000 * weight ) / ( cost * COST_INFLUENCE ); // Check against cost of getting there if( weight > bestWeight ) { bestWeight = weight; bestGoalEnt = goalEnt; } } if( bestGoalEnt ) { self->ai->goalEnt = bestGoalEnt; AI_SetGoal( self, bestGoalEnt->node ); if( self->ai->goalEnt != NULL && nav.debugMode && bot_showlrgoal->integer ) G_PrintChasersf( self, "%s: selected a %s at node %d for LR goal. (weight %f)\n", self->ai->pers.netname, self->ai->goalEnt->ent->classname, self->ai->goalEnt->node, bestWeight ); return; } if( nav.debugMode && bot_showlrgoal->integer ) G_PrintChasersf( self, "%s: did not find a LR goal.\n", self->ai->pers.netname ); #undef WEIGHT_MAXDISTANCE_FACTOR #undef COST_INFLUENCE }
/* ** CG_DrawChat */ void CG_DrawChat( cg_gamechat_t *chat, int x, int y, char *fontName, struct qfontface_s *font, int fontSize, int width, int height, int padding_x, int padding_y, vec4_t backColor, struct shader_s *backShader ) { int i, j; int s, e, w; int utf_len; int l, total_lines, lines; int x_offset, y_offset; int font_height; int pass; int lastcolor; int message_mode; int wait_time, fade_time; const cg_gamemessage_t *msg; const char *text; char tstr[GAMECHAT_STRING_SIZE]; vec4_t fontColor; bool chat_active = false; bool background_drawn = false; int corner_radius = 12 * cgs.vidHeight / 600; int background_y; int first_candidate; font_height = trap_SCR_FontHeight( font ); message_mode = (int)trap_Cvar_Value( "con_messageMode" ); chat_active = ( chat->lastMsgTime + GAMECHAT_WAIT_IN_TIME + GAMECHAT_FADE_IN_TIME > cg.realTime || message_mode ); lines = 0; total_lines = /*!message_mode ? 0 : */ 1; if( chat_active ) { wait_time = GAMECHAT_WAIT_IN_TIME; fade_time = GAMECHAT_FADE_IN_TIME; } else { wait_time = GAMECHAT_WAIT_OUT_TIME; fade_time = GAMECHAT_FADE_OUT_TIME; } if( chat_active != chat->lastActive ) { // smooth fade ins and fade outs chat->lastActiveChangeTime = cg.realTime - ( 1.0 - chat->activeFrac ) * ( wait_time + fade_time ); } if( cg.realTime >= chat->lastActiveChangeTime + wait_time ) { int time_diff, time_interval; time_diff = cg.realTime - ( chat->lastActiveChangeTime + wait_time ); time_interval = fade_time; if( time_diff <= time_interval ) { chat->activeFrac = (float)time_diff / time_interval; } else { chat->activeFrac = 1; } } else { chat->activeFrac = 0; } if( chat_active ) { backColor[3] *= chat->activeFrac; } else { backColor[3] *= ( 1.0 - chat->activeFrac ); } for( i = 0; i < GAMECHAT_STACK_SIZE; i++ ) { bool old_msg; l = chat->nextMsg - 1 - i; if( l < 0 ) { l = GAMECHAT_STACK_SIZE + l; } msg = &chat->messages[l]; text = msg->text; old_msg = !message_mode && ( cg.realTime > msg->time + GAMECHAT_NOTIFY_TIME ); if( !background_drawn && backColor[3] ) { if( old_msg ) { // keep the box being drawn for a while to prevent it from flickering // upon arrival of the possibly entered chat message if( !( !chat_active && cg.realTime <= chat->lastActiveChangeTime + 200 ) ) { break; } } background_y = y; trap_R_DrawStretchPic( x, background_y, width, height - corner_radius, 0.0f, 0.0f, 1.0f, 0.5f, backColor, backShader ); background_y += height - corner_radius; if( trap_IN_IME_GetCandidates( NULL, 0, 10, NULL, &first_candidate ) ) { int candidates_height = ( first_candidate ? 3 : 5 ) * font_height; trap_R_DrawStretchPic( x, background_y, width, candidates_height, 0.0f, 0.5f, 1.0f, 0.5f, backColor, backShader ); background_y += candidates_height; } trap_R_DrawStretchPic( x, background_y, corner_radius, corner_radius, 0.0f, 0.5f, 0.5f, 1.0f, backColor, backShader ); trap_R_DrawStretchPic( x + corner_radius, background_y, width - corner_radius * 2, corner_radius, 0.5f, 0.5f, 0.5f, 1.0f, backColor, backShader ); trap_R_DrawStretchPic( x + width - corner_radius, background_y, corner_radius, corner_radius, 0.5f, 0.5f, 1.0f, 1.0f, backColor, backShader ); background_drawn = true; } // unless user is typing something, only display recent messages if( old_msg ) { break; } pass = 0; lines = 0; lastcolor = ColorIndex( COLOR_WHITE ); parse_string: l = 1; s = e = 0; while( 1 ) { int len; memset( tstr, 0, sizeof( tstr ) ); // skip whitespaces at start for( ; text[s] == '\n' || Q_IsBreakingSpace( text + s ); s = Q_Utf8SyncPos( text, s + 1, UTF8SYNC_RIGHT ) ) ; // empty string if( !text[s] ) { break; } w = -1; len = trap_SCR_StrlenForWidth( text + s, font, width - padding_x * 2 ); clamp_low( len, 1 ); for( j = s; ( j < ( s + len ) ) && text[j] != '\0'; j += utf_len ) { utf_len = Q_Utf8SyncPos( text + j, 1, UTF8SYNC_RIGHT ); memcpy( tstr + j - s, text + j, utf_len ); if( text[j] == '\n' || Q_IsBreakingSpace( text + j ) ) { w = j; // last whitespace } if( text[j] == '\n' ) { break; } } e = j; // end // try to word avoid splitting words, unless no other options if( text[j] != '\0' && w > 0 ) { // stop at the last encountered whitespace j = w; } tstr[j - s] = '\0'; Vector4Copy( color_table[lastcolor], fontColor ); fontColor[3] = chat_active ? chat->activeFrac : 1.0 - chat->activeFrac; if( pass ) { // now actually render the line x_offset = padding_x; y_offset = height - padding_y - font_height - ( total_lines + lines - l ) * ( font_height + 2 ); if( y_offset < padding_y ) { break; } trap_SCR_DrawClampString( x + x_offset, y + y_offset, tstr, x + padding_x, y + padding_y, x - padding_x + width, y - padding_y + height, font, fontColor ); l++; } else { // increase the lines counter lines++; } if( !text[j] ) { // fast path: we don't need two passes in case of one-liners.. if( lines == 1 ) { x_offset = padding_x; y_offset = height - font_height - total_lines * ( font_height + 2 ); if( y_offset < padding_y ) { break; } trap_SCR_DrawClampString( x + x_offset, y + y_offset, tstr, x + padding_x, y + padding_y, x - padding_x + width, y - padding_y + height, font, fontColor ); total_lines++; pass++; } break; } if( pass ) { // grab the last color token to carry it over to the next line lastcolor = Q_ColorStrLastColor( lastcolor, tstr, j - s ); } s = j; } if( !pass ) { pass++; goto parse_string; } else { total_lines += lines; } } // let the engine know where the input line should be drawn trap_SCR_DrawChat( x + padding_x, y + height - padding_y - font_height, width - padding_x, font ); chat->lastActive = chat_active; }
/* * CG_AddLocalEntities */ void CG_AddLocalEntities( void ) { #define FADEINFRAMES 2 int f; lentity_t *le, *next, *hnode; entity_t *ent; float scale, frac, fade, time, scaleIn, fadeIn; float backlerp; vec3_t angles; time = cg.frameTime; backlerp = 1.0f - cg.lerpfrac; hnode = &cg_localents_headnode; for( le = hnode->next; le != hnode; le = next ) { next = le->next; frac = ( cg.time - le->start ) * 0.01f; f = ( int )floor( frac ); clamp_low( f, 0 ); // it's time to DIE if( f >= le->frames - 1 ) { le->type = LE_FREE; CG_FreeLocalEntity( le ); continue; } if( le->frames > 1 ) { scale = 1.0f - frac / ( le->frames - 1 ); scale = bound( 0.0f, scale, 1.0f ); fade = scale * 255.0f; // quick fade in, if time enough if( le->frames > FADEINFRAMES * 2 ) { scaleIn = frac / (float)FADEINFRAMES; clamp( scaleIn, 0.0f, 1.0f ); fadeIn = scaleIn * 255.0f; } else fadeIn = 255.0f; } else { scale = 1.0f; fade = 255.0f; fadeIn = 255.0f; } ent = &le->ent; if( le->light && scale ) CG_AddLightToScene( ent->origin, le->light * scale, le->lightcolor[0], le->lightcolor[1], le->lightcolor[2], NULL ); if( le->type == LE_LASER ) { CG_QuickPolyBeam( ent->origin, ent->origin2, ent->radius, ent->customShader ); // wsw : jalfixme: missing the color (comes inside ent->skinnum) continue; } if( le->type == LE_DASH_SCALE ) { if( f < 1 ) ent->scale = 0.2 * frac; else { VecToAngles( ent->axis[1], angles ); ent->axis[1][1] += 0.005f *sin( DEG2RAD ( angles[YAW] ) ); //length ent->axis[1][0] += 0.005f *cos( DEG2RAD ( angles[YAW] ) ); //length ent->axis[0][1] += 0.008f *cos( DEG2RAD ( angles[YAW] ) ); //width ent->axis[0][0] -= 0.008f *sin( DEG2RAD ( angles[YAW] ) ); //width ent->axis[2][2] -= 0.052f; //height if( ent->axis[2][2] <= 0 ) { le->type = LE_FREE; CG_FreeLocalEntity( le ); } } } if( le->type == LE_DASH_SCALE_2 ) { if( f < 1 ) ent->scale = 0.25 * frac; else { VecToAngles( ent->axis[1], angles ); ent->axis[1][1] += 0.005f *sin( DEG2RAD ( angles[YAW] ) ); //length ent->axis[1][0] += 0.005f *cos( DEG2RAD ( angles[YAW] ) ); //length ent->axis[0][1] += 0.008f *cos( DEG2RAD ( angles[YAW] ) ); //width ent->axis[0][0] -= 0.008f *sin( DEG2RAD ( angles[YAW] ) ); //width ent->axis[2][2] -= 0.018f; //height ent->origin[1] -= 0.6f *sin( DEG2RAD ( angles[YAW] ) ); //velocity ent->origin[0] -= 0.6f *cos( DEG2RAD ( angles[YAW] ) ); //velocity if( ent->axis[2][2] <= 0 ) { le->type = LE_FREE; CG_FreeLocalEntity( le ); } } } if( le->type == LE_PUFF_SCALE ) { if( frac < 1 ) ent->scale = 7.0f*frac; else ent->scale = 7.0f - 4.0f*( frac-1 ); if( ent->scale < 0 ) { le->type = LE_FREE; CG_FreeLocalEntity( le ); } } if( le->type == LE_PUFF_SCALE_2 ) { if( le->frames - f < 4 ) ent->scale = 1.0f - 1.0f * ( frac - abs( 4-le->frames ) )/4; } if( le->type == LE_PUFF_SHRINK ) { if( frac < 3 ) ent->scale = 1.0f - 0.2f * frac/4; else { ent->scale = 0.8 - 0.8*( frac-3 )/3; VectorScale( le->velocity, 0.85f, le->velocity ); } } if( le->type == LE_EXPLOSION_TRACER ) { if( cg.time - ent->rotation > 10.0f ) { ent->rotation = cg.time; if( ent->radius - 16*frac > 4 ) CG_Explosion_Puff( ent->origin, ent->radius-16*frac, le->frames - f ); } } switch( le->type ) { case LE_NO_FADE: break; case LE_RGB_FADE: fade = min( fade, fadeIn ); ent->shaderRGBA[0] = ( qbyte )( fade * le->color[0] ); ent->shaderRGBA[1] = ( qbyte )( fade * le->color[1] ); ent->shaderRGBA[2] = ( qbyte )( fade * le->color[2] ); break; case LE_SCALE_ALPHA_FADE: fade = min( fade, fadeIn ); ent->scale = 1.0f + 1.0f / scale; ent->scale = min( ent->scale, 5.0f ); ent->shaderRGBA[3] = ( qbyte )( fade * le->color[3] ); break; case LE_INVERSESCALE_ALPHA_FADE: fade = min( fade, fadeIn ); ent->scale = scale + 0.1f; clamp( ent->scale, 0.1f, 1.0f ); ent->shaderRGBA[3] = ( qbyte )( fade * le->color[3] ); break; case LE_ALPHA_FADE: fade = min( fade, fadeIn ); ent->shaderRGBA[3] = ( qbyte )( fade * le->color[3] ); break; default: break; } ent->backlerp = backlerp; if( le->bounce ) { trace_t trace; vec3_t next_origin; VectorMA( ent->origin, time, le->velocity, next_origin ); CG_Trace( &trace, ent->origin, debris_mins, debris_maxs, next_origin, 0, MASK_SOLID ); // remove the particle when going out of the map if( ( trace.contents & CONTENTS_NODROP ) || ( trace.surfFlags & SURF_SKY ) ) { le->frames = 0; } else if( trace.fraction != 1.0 ) // found solid { float dot; vec3_t vel; float xzyspeed; // Reflect velocity VectorSubtract( next_origin, ent->origin, vel ); dot = -2 *DotProduct( vel, trace.plane.normal ); VectorMA( vel, dot, trace.plane.normal, le->velocity ); //put new origin in the impact point, but move it out a bit along the normal VectorMA( trace.endpos, 1, trace.plane.normal, ent->origin ); //the entity has not speed enough. Stop checks xzyspeed = sqrt( le->velocity[0]*le->velocity[0] + le->velocity[1]*le->velocity[1] + le->velocity[2]*le->velocity[2] ); if( xzyspeed * time < 1.0f ) { trace_t traceground; vec3_t ground_origin; //see if we have ground VectorCopy( ent->origin, ground_origin ); ground_origin[2] += ( debris_mins[2] - 4 ); CG_Trace( &traceground, ent->origin, debris_mins, debris_maxs, ground_origin, 0, MASK_SOLID ); if( traceground.fraction != 1.0 ) { le->bounce = qfalse; VectorClear( le->velocity ); VectorClear( le->accel ); if( le->type == LE_EXPLOSION_TRACER ) { // blx le->type = LE_FREE; CG_FreeLocalEntity( le ); } } } else VectorScale( le->velocity, le->bounce * time, le->velocity ); } else { VectorCopy( ent->origin, ent->origin2 ); VectorCopy( next_origin, ent->origin ); } } else { VectorCopy( ent->origin, ent->origin2 ); VectorMA( ent->origin, time, le->velocity, ent->origin ); } VectorCopy( ent->origin, ent->lightingOrigin ); VectorMA( le->velocity, time, le->accel, le->velocity ); CG_AddEntityToScene( ent ); } }
/* * Con_DrawNotify * * Draws the last few lines of output transparently over the game top */ void Con_DrawNotify( void ) { int v; char *text; const char *say; const char *translated; int i; int time; char *s; v = 0; if( con_drawNotify->integer ) { for( i = min( NUM_CON_TIMES, con.numlines ) - 1; i >= 0; i-- ) { time = con.times[i]; if( time == 0 ) continue; time = cls.realtime - time; if( time > con_notifytime->value*1000 ) continue; text = con.text[i] ? con.text[i] : ""; SCR_DrawString( 8, v, ALIGN_LEFT_TOP, text, cls.fontSystemSmall, colorWhite ); v += SCR_strHeight( cls.fontSystemSmall ); } } if( cls.key_dest == key_message ) { int x, y; int width, prewidth; int promptwidth, cursorwidth; struct qfontface_s *font = NULL; if( con_chatCGame->integer ) { width = con_chatWidth->integer; if( *con_chatFontFamily->string && con_chatFontSize->integer ) { font = SCR_RegisterFont( con_chatFontFamily->string, con_chatFontStyle->integer, con_chatFontSize->integer ); } if( !font ) font = cls.fontSystemSmall; x = con_chatX->integer; y = con_chatY->integer; } else { width = viddef.width; x = 8; y = v; font = cls.fontSystemSmall; } // 48 is an arbitrary offset for not overlapping the FPS and clock prints width -= 48; cursorwidth = SCR_strWidth( "_", font, 0 ); if( chat_team ) { say = "say_team:"; } else { say = "say:"; } translated = L10n_TranslateString( "common", say ); if( !translated ) { translated = say; } SCR_DrawString( x, y, ALIGN_LEFT_TOP, translated, font, colorWhite ); promptwidth = SCR_strWidth( translated, font, 0 ) + SCR_strWidth( " ", font, 0 ); s = chat_buffer; prewidth = chat_linepos ? SCR_strWidth( s, font, chat_linepos ) : 0; // don't let the cursor go beyond the left screen edge clamp_high( chat_prestep, prewidth ); // don't let it go beyond the right screen edge clamp_low( chat_prestep, prewidth - ( width - promptwidth - cursorwidth ) ); // FIXME: we double the font height to compensate for alignment issues SCR_DrawClampString( x + promptwidth - chat_prestep, y, s, x + promptwidth, y, x + width, y + SCR_strHeight( font ) * 2, font, colorWhite ); if( (int)( cls.realtime>>8 )&1 ) SCR_DrawRawChar( x + promptwidth + prewidth - chat_prestep, y, '_', font, colorWhite ); }
/* * CG_AddLocalEntities */ void CG_AddLocalEntities( void ) { #define FADEINFRAMES 2 int f; lentity_t *le, *next, *hnode; entity_t *ent; float scale, frac, fade, time, scaleIn, fadeIn; float backlerp; vec3_t angles; time = cg.frameTime; backlerp = 1.0f - cg.lerpfrac; hnode = &cg_localents_headnode; for( le = hnode->next; le != hnode; le = next ) { next = le->next; frac = ( cg.time - le->start ) * 0.01f; f = ( int )floor( frac ); clamp_low( f, 0 ); // it's time to DIE if( f >= le->frames - 1 ) { le->type = LE_FREE; CG_FreeLocalEntity( le ); continue; } if( le->frames > 1 ) { scale = 1.0f - frac / ( le->frames - 1 ); scale = bound( 0.0f, scale, 1.0f ); fade = scale * 255.0f; // quick fade in, if time enough if( le->frames > FADEINFRAMES * 2 ) { scaleIn = frac / (float)FADEINFRAMES; clamp( scaleIn, 0.0f, 1.0f ); fadeIn = scaleIn * 255.0f; } else fadeIn = 255.0f; } else { scale = 1.0f; fade = 255.0f; fadeIn = 255.0f; } ent = &le->ent; if( le->light && scale ) CG_AddLightToScene( ent->origin, le->light * scale, le->lightcolor[0], le->lightcolor[1], le->lightcolor[2] ); if( le->type == LE_LASER ) { CG_QuickPolyBeam( ent->origin, ent->origin2, ent->radius, ent->customShader ); // wsw : jalfixme: missing the color (comes inside ent->skinnum) continue; } if( le->type == LE_DASH_SCALE ) { if( f < 1 ) ent->scale = 0.15 * frac; else { VecToAngles( &ent->axis[AXIS_RIGHT], angles ); ent->axis[1*3+1] += 0.005f *sin( DEG2RAD ( angles[YAW] ) ); //length ent->axis[1*3+0] += 0.005f *cos( DEG2RAD ( angles[YAW] ) ); //length ent->axis[0*3+1] += 0.008f *cos( DEG2RAD ( angles[YAW] ) ); //width ent->axis[0*3+0] -= 0.008f *sin( DEG2RAD ( angles[YAW] ) ); //width ent->axis[2*3+2] -= 0.052f; //height if( ent->axis[AXIS_UP+2] <= 0 ) { le->type = LE_FREE; CG_FreeLocalEntity( le ); } } } if( le->type == LE_PUFF_SCALE ) { if( le->frames - f < 4 ) ent->scale = 1.0f - 1.0f * ( frac - abs( 4-le->frames ) )/4; } if( le->type == LE_PUFF_SHRINK ) { if( frac < 3 ) ent->scale = 1.0f - 0.2f * frac/4; else { ent->scale = 0.8 - 0.8*( frac-3 )/3; VectorScale( le->velocity, 0.85f, le->velocity ); } } if( le->type == LE_EXPLOSION_TRACER ) { if( cg.time - ent->rotation > 10.0f ) { ent->rotation = cg.time; if( ent->radius - 16*frac > 4 ) CG_Explosion_Puff( ent->origin, ent->radius-16*frac, le->frames - f ); } } switch( le->type ) { case LE_NO_FADE: break; case LE_RGB_FADE: fade = min( fade, fadeIn ); ent->shaderRGBA[0] = ( uint8_t )( fade * le->color[0] ); ent->shaderRGBA[1] = ( uint8_t )( fade * le->color[1] ); ent->shaderRGBA[2] = ( uint8_t )( fade * le->color[2] ); break; case LE_SCALE_ALPHA_FADE: fade = min( fade, fadeIn ); ent->scale = 1.0f + 1.0f / scale; ent->scale = min( ent->scale, 5.0f ); ent->shaderRGBA[3] = ( uint8_t )( fade * le->color[3] ); break; case LE_INVERSESCALE_ALPHA_FADE: fade = min( fade, fadeIn ); ent->scale = scale + 0.1f; clamp( ent->scale, 0.1f, 1.0f ); ent->shaderRGBA[3] = ( uint8_t )( fade * le->color[3] ); break; case LE_ALPHA_FADE: fade = min( fade, fadeIn ); ent->shaderRGBA[3] = ( uint8_t )( fade * le->color[3] ); break; default: break; } ent->backlerp = backlerp; if ( le->avelocity[0] || le->avelocity[1] || le->avelocity[2] ) { VectorMA( le->angles, time, le->avelocity, le->angles ); AnglesToAxis( le->angles, le->ent.axis ); } // apply rotational friction if( le->bounce ) { // FIXME? int i; const float adj = 100 * 6 * time; // magic constants here for( i = 0; i < 3; i++ ) { if( le->avelocity[i] > 0.0f ) { le->avelocity[i] -= adj; if( le->avelocity[i] < 0.0f ) { le->avelocity[i] = 0.0f; } } else if ( le->avelocity[i] < 0.0f ) { le->avelocity[i] += adj; if ( le->avelocity[i] > 0.0f ) { le->avelocity[i] = 0.0f; } } } } if( le->bounce ) { trace_t trace; vec3_t next_origin; VectorMA( ent->origin, time, le->velocity, next_origin ); CG_Trace( &trace, ent->origin, debris_mins, debris_maxs, next_origin, 0, MASK_SOLID ); // remove the particle when going out of the map if( ( trace.contents & CONTENTS_NODROP ) || ( trace.surfFlags & SURF_SKY ) ) { le->frames = 0; } else if( trace.fraction != 1.0 ) // found solid { float dot; float xyzspeed, orig_xyzspeed; float bounce; orig_xyzspeed = VectorLength( le->velocity ); // Reflect velocity dot = DotProduct( le->velocity, trace.plane.normal ); VectorMA( le->velocity, -2.0f * dot, trace.plane.normal, le->velocity ); //put new origin in the impact point, but move it out a bit along the normal VectorMA( trace.endpos, 1, trace.plane.normal, ent->origin ); // make sure we don't gain speed from bouncing off bounce = 2.0f * le->bounce * 0.01f; if( bounce < 1.5f ) bounce = 1.5f; xyzspeed = orig_xyzspeed / bounce; VectorNormalize( le->velocity ); VectorScale( le->velocity, xyzspeed, le->velocity ); //the entity has not speed enough. Stop checks if( xyzspeed * time < 1.0f ) { trace_t traceground; vec3_t ground_origin; //see if we have ground VectorCopy( ent->origin, ground_origin ); ground_origin[2] += ( debris_mins[2] - 4 ); CG_Trace( &traceground, ent->origin, debris_mins, debris_maxs, ground_origin, 0, MASK_SOLID ); if( traceground.fraction != 1.0 ) { le->bounce = 0; VectorClear( le->velocity ); VectorClear( le->accel ); VectorClear( le->avelocity ); if( le->type == LE_EXPLOSION_TRACER ) { // blx le->type = LE_FREE; CG_FreeLocalEntity( le ); } } } } else { VectorCopy( ent->origin, ent->origin2 ); VectorCopy( next_origin, ent->origin ); } } else { VectorCopy( ent->origin, ent->origin2 ); VectorMA( ent->origin, time, le->velocity, ent->origin ); } VectorCopy( ent->origin, ent->lightingOrigin ); VectorMA( le->velocity, time, le->accel, le->velocity ); CG_AddEntityToScene( ent ); } }
void CG_RenderView( float frameTime, float realFrameTime, int realTime, unsigned int serverTime, float stereo_separation, unsigned int extrapolationTime, bool flipped ) { refdef_t *rd = &cg.view.refdef; // update time cg.realTime = realTime; cg.frameTime = frameTime; cg.realFrameTime = realFrameTime; cg.frameCount++; cg.time = serverTime; if( !cgs.precacheDone || !cg.frame.valid ) { CG_Precache(); CG_DrawLoading(); return; } { float snapTime = ( cg.frame.serverTime - cg.oldFrame.serverTime ); if( !snapTime ) snapTime = cgs.snapFrameTime; // moved this from CG_Init here cgs.extrapolationTime = extrapolationTime; if( cg.oldFrame.serverTime == cg.frame.serverTime ) cg.lerpfrac = 1.0f; else cg.lerpfrac = ( (double)( cg.time - cgs.extrapolationTime ) - (double)cg.oldFrame.serverTime ) / (double)snapTime; if( cgs.extrapolationTime ) { cg.xerpTime = 0.001f * ( (double)cg.time - (double)cg.frame.serverTime ); cg.oldXerpTime = 0.001f * ( (double)cg.time - (double)cg.oldFrame.serverTime ); if( cg.time >= cg.frame.serverTime ) { cg.xerpSmoothFrac = (double)( cg.time - cg.frame.serverTime ) / (double)( cgs.extrapolationTime ); clamp( cg.xerpSmoothFrac, 0.0f, 1.0f ); } else { cg.xerpSmoothFrac = (double)( cg.frame.serverTime - cg.time ) / (double)( cgs.extrapolationTime ); clamp( cg.xerpSmoothFrac, -1.0f, 0.0f ); cg.xerpSmoothFrac = 1.0f - cg.xerpSmoothFrac; } clamp_low( cg.xerpTime, -( cgs.extrapolationTime * 0.001f ) ); //clamp( cg.xerpTime, -( cgs.extrapolationTime * 0.001f ), ( cgs.extrapolationTime * 0.001f ) ); //clamp( cg.oldXerpTime, 0, ( ( snapTime + cgs.extrapolationTime ) * 0.001f ) ); } else { cg.xerpTime = 0.0f; cg.xerpSmoothFrac = 0.0f; } } if( cg_showClamp->integer ) { if( cg.lerpfrac > 1.0f ) CG_Printf( "high clamp %f\n", cg.lerpfrac ); else if( cg.lerpfrac < 0.0f ) CG_Printf( "low clamp %f\n", cg.lerpfrac ); } clamp( cg.lerpfrac, 0.0f, 1.0f ); if( !cgs.configStrings[CS_WORLDMODEL][0] ) { CG_AddLocalSounds(); trap_R_DrawStretchPic( 0, 0, cgs.vidWidth, cgs.vidHeight, 0, 0, 1, 1, colorBlack, cgs.shaderWhite ); trap_S_Update( vec3_origin, vec3_origin, axis_identity, cgs.clientInfo[cgs.playerNum].name ); return; } // bring up the game menu after reconnecting if( !cgs.tv && !cgs.demoPlaying ) { if( ISREALSPECTATOR() && !cg.firstFrame ) { if( !cgs.gameMenuRequested ) { trap_Cmd_ExecuteText( EXEC_NOW, "gamemenu\n" ); } cgs.gameMenuRequested = true; } } if( !cg.viewFrameCount ) cg.firstViewRealTime = cg.realTime; CG_FlashGameWindow(); // notify player of important game events CG_CalcVrect(); // find sizes of the 3d drawing screen CG_TileClear(); // clear any dirty part of the background CG_ChaseCamButtons(); CG_RunLightStyles(); CG_ClearFragmentedDecals(); trap_R_ClearScene(); if( CG_DemoCam_Update() ) CG_SetupViewDef( &cg.view, CG_DemoCam_GetViewType(), flipped ); else CG_SetupViewDef( &cg.view, VIEWDEF_PLAYERVIEW, flipped ); CG_LerpEntities(); // interpolate packet entities positions CG_CalcViewWeapon( &cg.weapon ); CG_FireEvents( false ); CG_AddEntities(); CG_AddViewWeapon( &cg.weapon ); CG_AddLocalEntities(); CG_AddParticles(); CG_AddDlights(); CG_AddShadeBoxes(); CG_AddDecals(); CG_AddPolys(); CG_AddLightStyles(); #ifndef PUBLIC_BUILD CG_AddTest(); #endif // offset vieworg appropriately if we're doing stereo separation VectorMA( cg.view.origin, stereo_separation, &cg.view.axis[AXIS_RIGHT], rd->vieworg ); // never let it sit exactly on a node line, because a water plane can // disappear when viewed with the eye exactly on it. // the server protocol only specifies to 1/16 pixel, so add 1/16 in each axis rd->vieworg[0] += 1.0/PM_VECTOR_SNAP; rd->vieworg[1] += 1.0/PM_VECTOR_SNAP; rd->vieworg[2] += 1.0/PM_VECTOR_SNAP; AnglesToAxis( cg.view.angles, rd->viewaxis ); rd->rdflags = CG_RenderFlags(); // warp if underwater if( rd->rdflags & RDF_UNDERWATER ) { float phase = rd->time * 0.001 * WAVE_FREQUENCY * M_TWOPI; float v = WAVE_AMPLITUDE * ( sin( phase ) - 1.0 ) + 1; rd->fov_x *= v; rd->fov_y *= v; } CG_AddLocalSounds(); CG_SetSceneTeamColors(); // update the team colors in the renderer trap_R_RenderScene( &cg.view.refdef ); cg.oldAreabits = true; trap_S_Update( cg.view.origin, cg.view.velocity, cg.view.axis, cgs.clientInfo[cgs.playerNum].name ); CG_Draw2D(); CG_ResetTemporaryBoneposesCache(); // clear for next frame cg.viewFrameCount++; }