/* * 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 ); }
void Bot::CheckAlertSpots(const StaticVector<edict_t *, MAX_CLIENTS> &visibleTargets) { float scores[MAX_ALERT_SPOTS]; // First compute scores (good for instruction cache) for (unsigned i = 0; i < alertSpots.size(); ++i) { float score = 0.0f; const auto &alertSpot = alertSpots[i]; const float squareRadius = alertSpot.radius * alertSpot.radius; const float invRadius = 1.0f / alertSpot.radius; for (const edict_t *ent: visibleTargets) { float squareDistance = DistanceSquared(ent->s.origin, alertSpot.origin.Data()); if (squareDistance > squareRadius) continue; float distance = Q_RSqrt(squareDistance + 0.001f); score += 1.0f - distance * invRadius; // Put likely case first if (!(ent->s.effects & EF_CARRIER)) score *= alertSpot.regularEnemyInfluenceScale; else score *= alertSpot.carrierEnemyInfluenceScale; } // Clamp score by a max value clamp_high(score, 3.0f); // Convert score to [0, 1] range score /= 3.0f; // Get a square root of score (values closer to 0 gets scaled more than ones closer to 1) score = 1.0f / Q_RSqrt(score + 0.001f); // Sanitize clamp(score, 0.0f, 1.0f); scores[i] = score; } // Then call callbacks const unsigned levelTime = level.time; for (unsigned i = 0; i < alertSpots.size(); ++i) { auto &alertSpot = alertSpots[i]; unsigned nonReportedFor = levelTime - alertSpot.lastReportedAt; if (nonReportedFor >= 1000) alertSpot.lastReportedScore = 0.0f; // Since scores are sanitized, they are in range [0.0f, 1.0f], and abs(scoreDelta) is in range [-1.0f, 1.0f]; float scoreDelta = scores[i] - alertSpot.lastReportedScore; if (scoreDelta >= 0) { if (nonReportedFor >= 1000 - scoreDelta * 500) alertSpot.Alert(this, scores[i]); } else { if (nonReportedFor >= 500 - scoreDelta * 500) alertSpot.Alert(this, scores[i]); } } }
/* * IN_IME_GetCandidates */ unsigned int IN_IME_GetCandidates( char * const *cands, size_t candSize, unsigned int maxCands, int *selected, int *firstKey ) { size_t candListSize; CANDIDATELIST *candList = in_winime_candList; unsigned int i; if( selected ) { *selected = -1; } if( firstKey ) { *firstKey = 1; } if( !in_winime_enabled ) { return 0; } candListSize = qimmGetCandidateList( in_winime_context, 0, NULL, 0 ); if( !candListSize ) { return 0; } if( candListSize > in_winime_candListSize ) { candList = Q_realloc( candList, candListSize ); if( !candList ) { return 0; } in_winime_candList = candList; in_winime_candListSize = candListSize; } if( qimmGetCandidateList( in_winime_context, 0, candList, candListSize ) != candListSize ) { return 0; } clamp_high( maxCands, candList->dwPageSize ); if( ( candList->dwPageStart + maxCands ) > candList->dwCount ) { maxCands = candList->dwCount - candList->dwPageStart; } if( cands && candSize ) { for( i = 0; i < maxCands; i++ ) Q_WCharToUtf8String( ( const WCHAR * )( ( const char * )candList + candList->dwOffset[candList->dwPageStart + i] ), cands[i], candSize ); } if( selected && ( candList->dwSelection >= candList->dwPageStart ) && ( candList->dwSelection < ( candList->dwPageStart + maxCands ) ) ) { *selected = ( int )candList->dwSelection - ( int )candList->dwPageStart; } if( firstKey ) { if( !( qimmGetProperty( GetKeyboardLayout( 0 ), IGP_PROPERTY ) & IME_PROP_CANDLIST_START_FROM_1 ) ) { *firstKey = 0; } } return maxCands; }
/* * 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 ); }
/* * Con_Linefeed */ static void Con_Linefeed( void ) { // shift scrollback text up in the buffer to make room for a new line if (con.numlines == con.totallines ) Q_free( con.text[con.numlines - 1] ); memmove( con.text + 1, con.text, sizeof( con.text[0] ) * min( con.numlines, con.totallines - 1 ) ); con.text[0] = NULL; // shift the timings array memmove( con.times + 1, con.times, sizeof( con.times[0] ) * ( NUM_CON_TIMES - 1 ) ); con.x = 0; if( con.display ) { // the console is scrolled up, stay in the same place if possible con.display++; clamp_high( con.display, con.totallines - 1 ); } con.numlines++; clamp_high( con.numlines, con.totallines ); }
void AiEntityPhysicsState::UpdateAreaNums() { const AiAasWorld *aasWorld = AiAasWorld::Instance(); this->currAasAreaNum = ( decltype( this->currAasAreaNum ) )aasWorld->FindAreaNum( Origin() ); // Use a computation shortcut when entity is on ground if( this->groundEntNum >= 0 ) { this->droppedToFloorOriginOffset = ( decltype( this->droppedToFloorOriginOffset ) )( -playerbox_stand_mins[2] ); this->droppedToFloorOriginOffset += 4.0f; SetHeightOverGround( 0 ); Vec3 droppedOrigin( Origin() ); droppedOrigin.Z() -= this->droppedToFloorOriginOffset; this->droppedToFloorAasAreaNum = ( decltype( this->droppedToFloorAasAreaNum ) )aasWorld->FindAreaNum( droppedOrigin ); return; } // Use a computation shortcut when the current area is grounded if( aasWorld->AreaSettings()[this->currAasAreaNum].areaflags & AREA_GROUNDED ) { float areaMinsZ = aasWorld->Areas()[this->currAasAreaNum].mins[2]; float selfZ = Self()->s.origin[2]; float heightOverGround_ = selfZ - areaMinsZ + playerbox_stand_maxs[2]; clamp_high( heightOverGround_, GROUND_TRACE_DEPTH ); SetHeightOverGround( heightOverGround_ ); this->droppedToFloorOriginOffset = ( decltype( this->droppedToFloorOriginOffset ) )( heightOverGround_ - 4.0f ); this->droppedToFloorAasAreaNum = this->currAasAreaNum; return; } // Try drop an origin from air to floor trace_t trace; edict_t *ent = const_cast<edict_t *>( Self() ); Vec3 traceEnd( Origin() ); traceEnd.Z() -= GROUND_TRACE_DEPTH; G_Trace( &trace, this->origin, ent->r.mins, ent->r.maxs, traceEnd.Data(), ent, MASK_PLAYERSOLID ); // Check not only whether there is a hit but test whether is it really a ground (and not a wall or obstacle) if( trace.fraction != 1.0f && Origin()[2] - trace.endpos[2] > -playerbox_stand_mins[2] ) { float heightOverGround_ = trace.fraction * GROUND_TRACE_DEPTH + playerbox_stand_mins[2]; this->droppedToFloorOriginOffset = ( decltype( this->droppedToFloorOriginOffset ) )( -playerbox_stand_mins[2] ); this->droppedToFloorOriginOffset -= heightOverGround_ - 4.0f; SetHeightOverGround( heightOverGround_ ); Vec3 droppedOrigin( Origin() ); droppedOrigin.Z() -= this->droppedToFloorOriginOffset; this->droppedToFloorAasAreaNum = ( decltype( this->droppedToFloorAasAreaNum ) )aasWorld->FindAreaNum( droppedOrigin ); return; } this->droppedToFloorOriginOffset = 0; SetHeightOverGround( std::numeric_limits<float>::infinity() ); this->droppedToFloorAasAreaNum = this->currAasAreaNum; }
void UI_Main::gamepadCursorMove( void ) { int64_t time = trap::Milliseconds(); static int64_t lastTime; if( !lastTime ) { lastTime = time; return; } if( lastTime == time ) { return; } int frameTimeMsec = time - lastTime; clamp_high( frameTimeMsec, 100 ); gamepadStickCursorMove( frameTimeMsec ); gamepadDpadCursorMove( frameTimeMsec ); }
/* * CG_StartFallKickEffect */ void CG_StartFallKickEffect( int bounceTime ) { if( !cg_viewBob->integer ) { cg.fallEffectTime = 0; cg.fallEffectRebounceTime = 0; return; } if( cg.fallEffectTime > cg.time ) cg.fallEffectRebounceTime = 0; bounceTime += 200; clamp_high( bounceTime, 400 ); cg.fallEffectTime = cg.time + bounceTime; if( cg.fallEffectRebounceTime ) cg.fallEffectRebounceTime = cg.time - ( ( cg.time - cg.fallEffectRebounceTime ) * 0.5 ); else cg.fallEffectRebounceTime = cg.time; }
void UI_Main::gamepadDpadCursorMove( int frameTimeMsec ) { float frameTime = frameTimeMsec * 0.001f; static float holdTime; static float x, y; clamp_high( frameTime, 0.1f ); int dx = trap::Key_IsDown( K_DPAD_RIGHT ) - trap::Key_IsDown( K_DPAD_LEFT ); int dy = trap::Key_IsDown( K_DPAD_DOWN ) - trap::Key_IsDown( K_DPAD_UP ); if( !dx && !dy ) { holdTime = x = y = 0.0f; return; } // Goes from half minimum screen height to double minimum screen height. float speed = ( 600.0f * 0.5f ) + bound( 0.0f, holdTime - 0.25f, 1.5f ) * 600.0f; if( dx && dy ) { speed *= 0.707106f; } speed *= refreshState.pixelRatio * frameTime; if( dx ) { x += ( ( dx < 0 ) ? -1.0f : 1.0f ) * speed; } else { x = 0.0f; } if( dy ) { y += ( ( dy < 0 ) ? -1.0f : 1.0f ) * speed; } else { y = 0.0f; } holdTime += frameTime; int mx = ( int )x, my = ( int )y; x -= ( float )mx; y -= ( float )my; mouseMove( UI_CONTEXT_MAIN, frameTimeMsec, mx, my, false, true ); }
void UI_Main::gamepadCursorMove( void ) { unsigned int time = trap::Milliseconds(); static unsigned int lastTime; if( !lastTime ) { lastTime = time; return; } float frameTime = ( time - lastTime ) * 0.001f; lastTime = time; if( !frameTime ) { return; } clamp_high( frameTime, 0.1f ); gamepadStickCursorMove( frameTime ); gamepadDpadCursorMove( frameTime ); }
void W_Fire_Electrobolt_FullInstant( edict_t *self, vec3_t start, vec3_t angles, float maxdamage, float mindamage, int maxknockback, int minknockback, int stun, int range, int minDamageRange, int mod, int timeDelta ) { vec3_t from, end, dir; trace_t tr; edict_t *ignore, *event, *hit, *damaged; int mask; qboolean missed = qtrue; int dmgflags = 0; #define FULL_DAMAGE_RANGE g_projectile_prestep->value if( GS_Instagib() ) maxdamage = mindamage = 9999; AngleVectors( angles, dir, NULL, NULL ); VectorMA( start, range, dir, end ); VectorCopy( start, from ); ignore = self; hit = damaged = NULL; mask = MASK_SHOT; if( GS_RaceGametype() ) mask = MASK_SOLID; clamp_high( mindamage, maxdamage ); clamp_high( minknockback, maxknockback ); clamp_high( minDamageRange, range ); if( minDamageRange <= FULL_DAMAGE_RANGE ) minDamageRange = FULL_DAMAGE_RANGE + 1; if( range <= FULL_DAMAGE_RANGE + 1 ) range = FULL_DAMAGE_RANGE + 1; tr.ent = -1; while( ignore ) { G_Trace4D( &tr, from, NULL, NULL, end, ignore, mask, timeDelta ); VectorCopy( tr.endpos, from ); ignore = NULL; if( tr.ent == -1 ) break; // some entity was touched hit = &game.edicts[tr.ent]; if( hit == world ) // stop dead if hit the world break; if( hit->movetype == MOVETYPE_NONE || hit->movetype == MOVETYPE_PUSH ) break; // allow trail to go through BBOX entities (players, gibs, etc) if( !ISBRUSHMODEL( hit->s.modelindex ) ) ignore = hit; if( ( hit != self ) && ( hit->takedamage ) ) { float frac, damage, knockback, dist; dist = DistanceFast( tr.endpos, start ); if( dist <= FULL_DAMAGE_RANGE ) frac = 0.0f; else { frac = ( dist - FULL_DAMAGE_RANGE ) / (float)( minDamageRange - FULL_DAMAGE_RANGE ); clamp( frac, 0.0f, 1.0f ); } damage = maxdamage - ( ( maxdamage - mindamage ) * frac ); knockback = maxknockback - ( ( maxknockback - minknockback ) * frac ); //G_Printf( "mindamagerange %i frac %.1f damage %i\n", minDamageRange, 1.0f - frac, (int)damage ); G_Damage( hit, self, self, dir, dir, tr.endpos, damage, knockback, stun, dmgflags, mod ); // spawn a impact event on each damaged ent event = G_SpawnEvent( EV_BOLT_EXPLOSION, DirToByte( tr.plane.normal ), tr.endpos ); event->s.firemode = FIRE_MODE_STRONG; if( hit->r.client ) missed = qfalse; damaged = hit; } } if( missed && self->r.client ) G_AwardPlayerMissedElectrobolt( self, mod ); // send the weapon fire effect event = G_SpawnEvent( EV_ELECTROTRAIL, ENTNUM( self ), start ); event->r.svflags = SVF_TRANSMITORIGIN2; VectorScale( dir, 1024, event->s.origin2 ); event->s.firemode = FIRE_MODE_STRONG; #undef FULL_DAMAGE_RANGE }
/* * W_Fire_Electrobolt_Combined */ void W_Fire_Electrobolt_Combined( edict_t *self, vec3_t start, vec3_t angles, float maxdamage, float mindamage, float maxknockback, float minknockback, int stun, int range, int mod, int timeDelta ) { vec3_t from, end, dir; trace_t tr; edict_t *ignore, *event, *hit, *damaged; int mask; qboolean missed = qtrue; int dmgflags = 0; int fireMode; #ifdef ELECTROBOLT_TEST fireMode = FIRE_MODE_WEAK; #else fireMode = FIRE_MODE_STRONG; #endif if( GS_Instagib() ) maxdamage = mindamage = 9999; AngleVectors( angles, dir, NULL, NULL ); VectorMA( start, range, dir, end ); VectorCopy( start, from ); ignore = self; hit = damaged = NULL; mask = MASK_SHOT; if( GS_RaceGametype() ) mask = MASK_SOLID; clamp_high( mindamage, maxdamage ); clamp_high( minknockback, maxknockback ); tr.ent = -1; while( ignore ) { G_Trace4D( &tr, from, NULL, NULL, end, ignore, mask, timeDelta ); VectorCopy( tr.endpos, from ); ignore = NULL; if( tr.ent == -1 ) break; // some entity was touched hit = &game.edicts[tr.ent]; if( hit == world ) // stop dead if hit the world break; if( hit->movetype == MOVETYPE_NONE || hit->movetype == MOVETYPE_PUSH ) break; // allow trail to go through BBOX entities (players, gibs, etc) if( !ISBRUSHMODEL( hit->s.modelindex ) ) ignore = hit; if( ( hit != self ) && ( hit->takedamage ) ) { float frac, damage, knockback; frac = DistanceFast( tr.endpos, start ) / (float)range; clamp( frac, 0.0f, 1.0f ); damage = maxdamage - ( ( maxdamage - mindamage ) * frac ); knockback = maxknockback - ( ( maxknockback - minknockback ) * frac ); G_Damage( hit, self, self, dir, dir, tr.endpos, damage, knockback, stun, dmgflags, mod ); // spawn a impact event on each damaged ent event = G_SpawnEvent( EV_BOLT_EXPLOSION, DirToByte( tr.plane.normal ), tr.endpos ); event->s.firemode = fireMode; if( hit->r.client ) missed = qfalse; damaged = hit; } } if( missed && self->r.client ) G_AwardPlayerMissedElectrobolt( self, mod ); // send the weapon fire effect event = G_SpawnEvent( EV_ELECTROTRAIL, ENTNUM( self ), start ); event->r.svflags = SVF_TRANSMITORIGIN2; VectorScale( dir, 1024, event->s.origin2 ); event->s.firemode = fireMode; if( !GS_Instagib() && tr.ent == -1 ) // didn't touch anything, not even a wall { edict_t *bolt; gs_weapon_definition_t *weapondef = GS_GetWeaponDef( self->s.weapon ); // fire a weak EB from the end position bolt = W_Fire_Electrobolt_Weak( self, end, angles, weapondef->firedef_weak.speed, mindamage, minknockback, minknockback, stun, weapondef->firedef_weak.timeout, mod, timeDelta ); bolt->enemy = damaged; } }
/* * G_RadiusDamage */ void G_RadiusDamage( edict_t *inflictor, edict_t *attacker, cplane_t *plane, edict_t *ignore, int mod ) { edict_t *ent = NULL; float dmgFrac, kickFrac, damage, knockback, stun; vec3_t pushDir; int timeDelta; float maxdamage, mindamage, maxknockback, minknockback, maxstun, minstun, radius; assert( inflictor ); maxdamage = inflictor->projectileInfo.maxDamage; mindamage = inflictor->projectileInfo.minDamage; maxknockback = inflictor->projectileInfo.maxKnockback; minknockback = inflictor->projectileInfo.minKnockback; maxstun = inflictor->projectileInfo.stun; minstun = 1; radius = inflictor->projectileInfo.radius; if( radius <= 1.0f || ( maxdamage <= 0.0f && maxknockback <= 0.0f ) ) return; clamp_high( mindamage, maxdamage ); clamp_high( minknockback, maxknockback ); clamp_high( minstun, maxstun ); while( ( ent = GClip_FindBoxInRadius4D( ent, inflictor->s.origin, radius, inflictor->timeDelta ) ) != NULL ) { if( ent == ignore || !ent->takedamage ) continue; if( ent == attacker && ent->r.client ) timeDelta = 0; else timeDelta = inflictor->timeDelta; G_SplashFrac4D( ENTNUM( ent ), inflictor->s.origin, radius, pushDir, &kickFrac, &dmgFrac, timeDelta ); damage = max( 0, mindamage + ( ( maxdamage - mindamage ) * dmgFrac ) ); stun = max( 0, minstun + ( ( maxstun - minstun ) * dmgFrac ) ); knockback = max( 0, minknockback + ( ( maxknockback - minknockback ) * kickFrac ) ); // weapon jumps hack : when knockback on self, use strong weapon definition if( ent == attacker && ent->r.client ) { gs_weapon_definition_t *weapondef = NULL; if( inflictor->s.type == ET_ROCKET ) weapondef = GS_GetWeaponDef( WEAP_ROCKETLAUNCHER ); else if( inflictor->s.type == ET_GRENADE ) weapondef = GS_GetWeaponDef( WEAP_GRENADELAUNCHER ); else if( inflictor->s.type == ET_PLASMA ) weapondef = GS_GetWeaponDef( WEAP_PLASMAGUN ); else if( inflictor->s.type == ET_BLASTER ) weapondef = GS_GetWeaponDef( WEAP_GUNBLADE ); if( weapondef ) { G_SplashFrac4D( ENTNUM( ent ), inflictor->s.origin, radius, pushDir, &kickFrac, NULL, 0 ); minknockback = weapondef->firedef.minknockback; maxknockback = weapondef->firedef.knockback; clamp_high( minknockback, maxknockback ); knockback = ( minknockback + ( (float)( maxknockback - minknockback ) * kickFrac ) ) * g_self_knockback->value; damage *= weapondef->firedef.selfdamage; } } if( knockback < 1.0f ) knockback = 0.0f; if( stun < 1.0f ) stun = 0.0f; if( damage <= 0.0f && knockback <= 0.0f && stun <= 0.0f ) continue; if( G_CanSplashDamage( ent, inflictor, plane ) ) G_Damage( ent, inflictor, attacker, pushDir, inflictor->velocity, inflictor->s.origin, damage, knockback, stun, DAMAGE_RADIUS, mod ); } }
size_t IN_IME_GetComposition( char *str, size_t strSize, size_t *cursorPos, size_t *convStart, size_t *convLen ) { WCHAR compStr[IN_WINIME_COMPSTR_LENGTH + 1]; char compAttr[IN_WINIME_COMPSTR_LENGTH + 1]; int len, attrLen, i, cursor, attr, start = -1; size_t cursorutf = 0, startutf = 0, convutflen = 0, ret = 0; if( !strSize ) { str = NULL; } if( str ) { str[0] = '\0'; } if( cursorPos ) { *cursorPos = 0; } if( convStart ) { *convStart = 0; } if( convLen ) { *convLen = 0; } if( !in_winime_enabled ) { return 0; } len = qimmGetCompositionString( in_winime_context, GCS_COMPSTR, compStr, sizeof( compStr ) ) / sizeof( WCHAR ); if( len <= 0 ) { return 0; } compStr[len] = 0; if( str ) { ret = Q_WCharToUtf8String( compStr, str, strSize ); } else { for( i = 0; i < len; i++ ) ret += Q_WCharUtf8Length( compStr[i] ); } if( cursorPos ) { cursor = LOWORD( qimmGetCompositionString( in_winime_context, GCS_CURSORPOS, NULL, 0 ) ); for( i = 0; ( i < cursor ) && ( i < len ); i++ ) cursorutf += Q_WCharUtf8Length( compStr[i] ); clamp_high( cursorutf, ret ); *cursorPos = cursorutf; } if( convStart || convLen ) { attrLen = qimmGetCompositionString( in_winime_context, GCS_COMPATTR, compAttr, sizeof( compAttr ) ); if( attrLen == len ) { for( i = 0; i < attrLen; i++ ) { attr = compAttr[i]; if( ( attr == ATTR_TARGET_CONVERTED ) || ( attr == ATTR_TARGET_NOTCONVERTED ) ) { if( start < 0 ) { start = startutf; } convutflen += Q_WCharUtf8Length( compStr[i] ); } else { if( start >= 0 ) { break; } startutf += Q_WCharUtf8Length( compStr[i] ); } } if( start >= 0 ) { if( start > ( int )ret ) { start = ret; } if( ( start + convutflen ) > ( int )ret ) { convutflen = ret - start; } if( convStart ) { *convStart = start; } if( convLen ) { *convLen = convutflen; } } } } return ret; }
/* * RFB_RegisterObject */ int RFB_RegisterObject( int width, int height, bool builtin, bool depthRB, bool stencilRB, bool colorRB, int samples, bool useFloat, bool sRGB ) { int i; int format; GLuint fbID; GLuint rbID = 0; r_fbo_t *fbo = NULL; if( !r_frambuffer_objects_initialized ) { return 0; } #ifdef GL_ES_VERSION_2_0 if( samples ) { return 0; } #else if( samples && !glConfig.ext.framebuffer_multisample ) { return 0; } #endif for( i = 0, fbo = r_framebuffer_objects; i < r_num_framebuffer_objects; i++, fbo++ ) { if( !fbo->objectID ) { // free slot goto found; } } if( i == MAX_FRAMEBUFFER_OBJECTS ) { Com_Printf( S_COLOR_YELLOW "RFB_RegisterObject: framebuffer objects limit exceeded\n" ); return 0; } clamp_high( samples, glConfig.maxFramebufferSamples ); i = r_num_framebuffer_objects++; fbo = r_framebuffer_objects + i; found: qglGenFramebuffersEXT( 1, &fbID ); memset( fbo, 0, sizeof( *fbo ) ); fbo->objectID = fbID; if( builtin ) { fbo->registrationSequence = -1; } else { fbo->registrationSequence = rsh.registrationSequence; } fbo->width = width; fbo->height = height; fbo->samples = samples; fbo->sRGB = sRGB; qglBindFramebufferEXT( GL_FRAMEBUFFER_EXT, fbo->objectID ); if( colorRB ) { format = glConfig.forceRGBAFramebuffers ? GL_RGBA : GL_RGB; if( useFloat ) { format = glConfig.forceRGBAFramebuffers ? GL_RGBA16F_ARB : GL_RGB16F_ARB; } qglGenRenderbuffersEXT( 1, &rbID ); fbo->colorRenderBuffer = rbID; qglBindRenderbufferEXT( GL_RENDERBUFFER_EXT, rbID ); #ifndef GL_ES_VERSION_2_0 if( samples ) { qglRenderbufferStorageMultisampleEXT( GL_RENDERBUFFER_EXT, samples, format, width, height ); } else #endif qglRenderbufferStorageEXT( GL_RENDERBUFFER_EXT, format, width, height ); } #ifndef GL_ES_VERSION_2_0 else { // until a color texture is attached, don't enable drawing to the buffer qglDrawBuffer( GL_NONE ); qglReadBuffer( GL_NONE ); } #endif if( depthRB ) { qglGenRenderbuffersEXT( 1, &rbID ); fbo->depthRenderBuffer = rbID; qglBindRenderbufferEXT( GL_RENDERBUFFER_EXT, rbID ); if( stencilRB ) { format = GL_DEPTH24_STENCIL8_EXT; } else if( glConfig.ext.depth24 ) { format = GL_DEPTH_COMPONENT24; } else if( glConfig.ext.depth_nonlinear ) { format = GL_DEPTH_COMPONENT16_NONLINEAR_NV; } else { format = GL_DEPTH_COMPONENT16; } #ifndef GL_ES_VERSION_2_0 if( samples ) { qglRenderbufferStorageMultisampleEXT( GL_RENDERBUFFER_EXT, samples, format, width, height ); } else #endif qglRenderbufferStorageEXT( GL_RENDERBUFFER_EXT, format, width, height ); if( stencilRB ) { fbo->stencilRenderBuffer = rbID; } } if( rbID ) { qglBindRenderbufferEXT( GL_RENDERBUFFER_EXT, 0 ); } if( fbo->colorRenderBuffer ) { qglFramebufferRenderbufferEXT( GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_RENDERBUFFER_EXT, fbo->colorRenderBuffer ); } if( fbo->depthRenderBuffer ) { qglFramebufferRenderbufferEXT( GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, fbo->depthRenderBuffer ); } if( fbo->stencilRenderBuffer ) { qglFramebufferRenderbufferEXT( GL_FRAMEBUFFER_EXT, GL_STENCIL_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, fbo->stencilRenderBuffer ); } if( colorRB && depthRB ) { if( !RFB_CheckObjectStatus() ) { goto fail; } } if( r_bound_framebuffer_objectID ) { qglBindFramebufferEXT( GL_FRAMEBUFFER_EXT, r_bound_framebuffer_object->objectID ); } else { qglBindFramebufferEXT( GL_FRAMEBUFFER_EXT, 0 ); } return i + 1; fail: RFB_DeleteObject( fbo ); qglBindFramebufferEXT( GL_FRAMEBUFFER_EXT, 0 ); return 0; }
/* * 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 ); }