double Vector2::Magnitude() const { return sqrt( DotProduct( *this ) ); }
/* ================ PM_DrawPhysEntBBox(int num) ================ */ void PM_DrawPhysEntBBox(int num, int pcolor, float life) { physent_t *pe; vec3_t org; int j; vec3_t tmp; vec3_t p[8]; float gap = BOX_GAP; vec3_t modelmins, modelmaxs; if(num >= pmove->numphysent || num <= 0) return; pe = &pmove->physents[num]; if(pe->model) { VectorCopy(pe->origin, org); pmove->PM_GetModelBounds(pe->model, modelmins, modelmaxs); for(j = 0; j < 8; j++) { tmp[0] = (j & 1) ? modelmins[0] - gap : modelmaxs[0] + gap; tmp[1] = (j & 2) ? modelmins[1] - gap : modelmaxs[1] + gap; tmp[2] = (j & 4) ? modelmins[2] - gap : modelmaxs[2] + gap; VectorCopy(tmp, p[j]); } // If the bbox should be rotated, do that if(pe->angles[0] || pe->angles[1] || pe->angles[2]) { vec3_t forward, right, up; AngleVectorsTranspose(pe->angles, forward, right, up); for(j = 0; j < 8; j++) { VectorCopy(p[j], tmp); p[j][0] = DotProduct(tmp, forward); p[j][1] = DotProduct(tmp, right); p[j][2] = DotProduct(tmp, up); } } // Offset by entity origin, if any. for(j = 0; j < 8; j++) VectorAdd(p[j], org, p[j]); for(j = 0; j < 6; j++) { PM_DrawRectangle( p[PM_boxpnt[j][1]], p[PM_boxpnt[j][0]], p[PM_boxpnt[j][2]], p[PM_boxpnt[j][3]], pcolor, life); } } else { for(j = 0; j < 8; j++) { tmp[0] = (j & 1) ? pe->mins[0] : pe->maxs[0]; tmp[1] = (j & 2) ? pe->mins[1] : pe->maxs[1]; tmp[2] = (j & 4) ? pe->mins[2] : pe->maxs[2]; VectorAdd(tmp, pe->origin, tmp); VectorCopy(tmp, p[j]); } for(j = 0; j < 6; j++) { PM_DrawRectangle( p[PM_boxpnt[j][1]], p[PM_boxpnt[j][0]], p[PM_boxpnt[j][2]], p[PM_boxpnt[j][3]], pcolor, life); } } }
/* ============= SV_Physics_Toss Toss, bounce, and fly movement. When onground, do nothing. ============= */ void SV_Physics_Toss( edict_t *ent ) { trace_t trace; vec3_t move; float backoff; edict_t *ground; SV_CheckWater( ent ); // regular thinking if( !SV_RunThink( ent )) return; ground = ent->v.groundentity; if( ent->v.velocity[2] > 0.0f || !SV_IsValidEdict( ground ) || ground->v.flags & (FL_MONSTER|FL_CLIENT) || svgame.globals->changelevel ) { ent->v.flags &= ~FL_ONGROUND; } // if on ground and not moving, return. if( ent->v.flags & FL_ONGROUND && VectorIsNull( ent->v.velocity )) { VectorClear( ent->v.avelocity ); if( VectorIsNull( ent->v.basevelocity )) return; // at rest } SV_CheckVelocity( ent ); // add gravity switch( ent->v.movetype ) { case MOVETYPE_FLY: case MOVETYPE_FLYMISSILE: case MOVETYPE_BOUNCEMISSILE: break; default: SV_AddGravity( ent ); break; } // move angles (with friction) switch( ent->v.movetype ) { case MOVETYPE_TOSS: case MOVETYPE_BOUNCE: SV_AngularMove( ent, host.frametime, ent->v.friction ); break; default: SV_AngularMove( ent, host.frametime, 0.0f ); break; } // move origin // Base velocity is not properly accounted for since this entity will move again // after the bounce without taking it into account VectorAdd( ent->v.velocity, ent->v.basevelocity, ent->v.velocity ); SV_CheckVelocity( ent ); VectorScale( ent->v.velocity, host.frametime, move ); VectorSubtract( ent->v.velocity, ent->v.basevelocity, ent->v.velocity ); trace = SV_PushEntity( ent, move, vec3_origin, NULL ); if( ent->free ) return; SV_CheckVelocity( ent ); if( trace.allsolid ) { // entity is trapped in another solid VectorClear( ent->v.avelocity ); VectorClear( ent->v.velocity ); return; } if( trace.fraction == 1.0f ) { SV_CheckWaterTransition( ent ); return; } if( ent->v.movetype == MOVETYPE_BOUNCE ) backoff = 2.0f - ent->v.friction; else if( ent->v.movetype == MOVETYPE_BOUNCEMISSILE ) backoff = 2.0f; else backoff = 1.0f; SV_ClipVelocity( ent->v.velocity, trace.plane.normal, ent->v.velocity, backoff ); // stop if on ground if( trace.plane.normal[2] > 0.7f ) { float vel; VectorAdd( ent->v.velocity, ent->v.basevelocity, move ); vel = DotProduct( move, move ); if( ent->v.velocity[2] < sv_gravity->value * host.frametime ) { // we're rolling on the ground, add static friction. ent->v.groundentity = trace.ent; ent->v.flags |= FL_ONGROUND; ent->v.velocity[2] = 0.0f; } if( vel < 900.0f || ( ent->v.movetype != MOVETYPE_BOUNCE && ent->v.movetype != MOVETYPE_BOUNCEMISSILE )) { ent->v.flags |= FL_ONGROUND; ent->v.groundentity = trace.ent; VectorClear( ent->v.avelocity ); VectorClear( ent->v.velocity ); } else { VectorScale( ent->v.velocity, (1.0f - trace.fraction) * host.frametime * 0.9f, move ); VectorMA( move, (1.0f - trace.fraction) * host.frametime * 0.9f, ent->v.basevelocity, move ); trace = SV_PushEntity( ent, move, vec3_origin, NULL ); if( ent->free ) return; } } // check for in water SV_CheckWaterTransition( ent ); }
//========================================================= // Hornet is flying, gently tracking target //========================================================= void CHornet::TrackTarget(void) { Vector vecFlightDir; Vector vecDirToEnemy; float flDelta; StudioFrameAdvance(); if (gpGlobals->time > m_flStopAttack) { SetTouch(NULL); SetThink(&CHornet::SUB_Remove); SetNextThink(0.1); return; } // UNDONE: The player pointer should come back after returning from another level if (m_hEnemy == NULL) {// enemy is dead. Look(512); m_hEnemy = BestVisibleEnemy(); } if (m_hEnemy != NULL && FVisible(m_hEnemy)) { m_vecEnemyLKP = m_hEnemy->BodyTarget(pev->origin); } else { m_vecEnemyLKP = m_vecEnemyLKP + pev->velocity * m_flFlySpeed * 0.1; } vecDirToEnemy = (m_vecEnemyLKP - pev->origin).Normalize(); if (pev->velocity.Length() < 0.1) vecFlightDir = vecDirToEnemy; else vecFlightDir = pev->velocity.Normalize(); // measure how far the turn is, the wider the turn, the slow we'll go this time. flDelta = DotProduct(vecFlightDir, vecDirToEnemy); if (flDelta < 0.5) {// hafta turn wide again. play sound switch (RANDOM_LONG(0, 2)) { case 0: EMIT_SOUND(ENT(pev), CHAN_VOICE, "hornet/ag_buzz1.wav", HORNET_BUZZ_VOLUME, ATTN_NORM); break; case 1: EMIT_SOUND(ENT(pev), CHAN_VOICE, "hornet/ag_buzz2.wav", HORNET_BUZZ_VOLUME, ATTN_NORM); break; case 2: EMIT_SOUND(ENT(pev), CHAN_VOICE, "hornet/ag_buzz3.wav", HORNET_BUZZ_VOLUME, ATTN_NORM); break; } } if (flDelta <= 0 && m_iHornetType == HORNET_TYPE_RED) {// no flying backwards, but we don't want to invert this, cause we'd go fast when we have to turn REAL far. flDelta = 0.25; } pev->velocity = (vecFlightDir + vecDirToEnemy).Normalize(); if (pev->owner && (pev->owner->v.flags & FL_MONSTER)) { // random pattern only applies to hornets fired by monsters, not players. pev->velocity.x += RANDOM_FLOAT(-0.10, 0.10);// scramble the flight dir a bit. pev->velocity.y += RANDOM_FLOAT(-0.10, 0.10); pev->velocity.z += RANDOM_FLOAT(-0.10, 0.10); } switch (m_iHornetType) { case HORNET_TYPE_RED: pev->velocity = pev->velocity * (m_flFlySpeed * flDelta);// scale the dir by the ( speed * width of turn ) SetNextThink(RANDOM_FLOAT(0.1, 0.3)); break; case HORNET_TYPE_ORANGE: pev->velocity = pev->velocity * m_flFlySpeed;// do not have to slow down to turn. SetNextThink(0.1);// fixed think time break; } pev->angles = UTIL_VecToAngles(pev->velocity); pev->solid = SOLID_BBOX; // if hornet is close to the enemy, jet in a straight line for a half second. // (only in the single player game) if (m_hEnemy != NULL && !g_pGameRules->IsMultiplayer()) { if (flDelta >= 0.4 && (pev->origin - m_vecEnemyLKP).Length() <= 300) { MESSAGE_BEGIN(MSG_PVS, SVC_TEMPENTITY, pev->origin); WRITE_BYTE(TE_SPRITE); WRITE_COORD(pev->origin.x); // pos WRITE_COORD(pev->origin.y); WRITE_COORD(pev->origin.z); WRITE_SHORT(iHornetPuff); // model // WRITE_BYTE( 0 ); // life * 10 WRITE_BYTE(2); // size * 10 WRITE_BYTE(128); // brightness MESSAGE_END(); switch (RANDOM_LONG(0, 2)) { case 0: EMIT_SOUND(ENT(pev), CHAN_VOICE, "hornet/ag_buzz1.wav", HORNET_BUZZ_VOLUME, ATTN_NORM); break; case 1: EMIT_SOUND(ENT(pev), CHAN_VOICE, "hornet/ag_buzz2.wav", HORNET_BUZZ_VOLUME, ATTN_NORM); break; case 2: EMIT_SOUND(ENT(pev), CHAN_VOICE, "hornet/ag_buzz3.wav", HORNET_BUZZ_VOLUME, ATTN_NORM); break; } pev->velocity = pev->velocity * 2; SetNextThink(1.0); // don't attack again m_flStopAttack = gpGlobals->time; } } }
void MakeRGBScales(const int threadnum) { int i; unsigned j; vec3_t delta; vec_t dist; int count; float trans[3]; float trans_one; patch_t* patch; patch_t* patch2; vec3_t origin; vec_t area; const vec_t* normal1; const vec_t* normal2; #ifdef HLRAD_TRANSPARENCY_CPP unsigned int fastfind_index = 0; #endif vec_t total; #ifdef HLRAD_TRANSFERDATA_COMPRESS transfer_raw_index_t* tIndex; float* tRGBData; transfer_raw_index_t* tIndex_All = (transfer_raw_index_t*)AllocBlock(sizeof(transfer_index_t) * MAX_PATCHES); float* tRGBData_All = (float*)AllocBlock(sizeof(float[3]) * MAX_PATCHES); #else transfer_raw_index_t* tIndex; rgb_transfer_data_t* tRGBData; transfer_raw_index_t* tIndex_All = (transfer_raw_index_t*)AllocBlock(sizeof(transfer_index_t) * MAX_PATCHES); rgb_transfer_data_t* tRGBData_All = (rgb_transfer_data_t*)AllocBlock(sizeof(rgb_transfer_data_t) * MAX_PATCHES); #endif count = 0; while (1) { i = GetThreadWork(); if (i == -1) break; patch = g_patches + i; patch->iIndex = 0; patch->iData = 0; #ifndef HLRAD_TRANSNONORMALIZE total = 0.0; #endif tIndex = tIndex_All; tRGBData = tRGBData_All; VectorCopy(patch->origin, origin); normal1 = getPlaneFromFaceNumber(patch->faceNumber)->normal; area = patch->area; #ifdef HLRAD_TRANSLUCENT vec3_t backorigin; vec3_t backnormal; if (patch->translucent_b) { VectorMA (patch->origin, -(g_translucentdepth + 2*PATCH_HUNT_OFFSET), normal1, backorigin); VectorSubtract (vec3_origin, normal1, backnormal); } #endif #ifdef HLRAD_DIVERSE_LIGHTING bool lighting_diversify; vec_t lighting_power; vec_t lighting_scale; int miptex = g_texinfo[g_dfaces[patch->faceNumber].texinfo].miptex; lighting_power = g_lightingconeinfo[miptex][0]; lighting_scale = g_lightingconeinfo[miptex][1]; lighting_diversify = (lighting_power != 1.0 || lighting_scale != 1.0); #endif // find out which patch2's will collect light // from patch // HLRAD_NOSWAP: patch collect light from patch2 for (j = 0, patch2 = g_patches; j < g_num_patches; j++, patch2++) { vec_t dot1; vec_t dot2; vec3_t transparency = {1.0,1.0,1.0}; #ifdef HLRAD_TRANSLUCENT bool useback; useback = false; #endif if (!g_CheckVisBit(i, j , transparency #ifdef HLRAD_TRANSPARENCY_CPP , fastfind_index #endif ) || (i == j)) { #ifdef HLRAD_TRANSLUCENT if (patch->translucent_b) { if (!CheckVisBitBackwards(i, j, backorigin, backnormal #ifdef HLRAD_HULLU , transparency #endif ) || (i==j)) { continue; } useback = true; } else { continue; } #else continue; #endif } normal2 = getPlaneFromFaceNumber(patch2->faceNumber)->normal; // calculate transferemnce VectorSubtract(patch2->origin, origin, delta); #ifdef HLRAD_TRANSLUCENT if (useback) { VectorSubtract (patch2->origin, backorigin, delta); } #endif #ifdef HLRAD_ACCURATEBOUNCE // move emitter back to its plane VectorMA (delta, -PATCH_HUNT_OFFSET, normal2, delta); #endif dist = VectorNormalize(delta); dot1 = DotProduct(delta, normal1); #ifdef HLRAD_TRANSLUCENT if (useback) { dot1 = DotProduct (delta, backnormal); } #endif dot2 = -DotProduct(delta, normal2); #ifdef HLRAD_ACCURATEBOUNCE #ifdef HLRAD_ACCURATEBOUNCE_ALTERNATEORIGIN bool light_behind_surface = false; if (dot1 <= NORMAL_EPSILON) { light_behind_surface = true; } #else if (dot1 <= NORMAL_EPSILON) { continue; } #endif if (dot2 * dist <= MINIMUM_PATCH_DISTANCE) { continue; } #endif #ifdef HLRAD_DIVERSE_LIGHTING if (lighting_diversify #ifdef HLRAD_ACCURATEBOUNCE_ALTERNATEORIGIN && !light_behind_surface #endif ) { dot1 = lighting_scale * pow (dot1, lighting_power); } #endif trans_one = (dot1 * dot2) / (dist * dist); // Inverse square falloff factoring angle between patch normals #ifdef HLRAD_TRANSWEIRDFIX #ifdef HLRAD_NOSWAP if (trans_one * patch2->area > 0.8f) { trans_one = 0.8f / patch2->area; } #else if (trans_one * area > 0.8f) { trans_one = 0.8f / area; } #endif #endif #ifdef HLRAD_ACCURATEBOUNCE if (dist < patch2->emitter_range - ON_EPSILON) { #ifdef HLRAD_ACCURATEBOUNCE_ALTERNATEORIGIN if (light_behind_surface) { trans_one = 0.0; } #endif vec_t sightarea; const vec_t *receiver_origin; const vec_t *receiver_normal; const Winding *emitter_winding; receiver_origin = origin; receiver_normal = normal1; #ifdef HLRAD_TRANSLUCENT if (useback) { receiver_origin = backorigin; receiver_normal = backnormal; } #endif emitter_winding = patch2->winding; sightarea = CalcSightArea (receiver_origin, receiver_normal, emitter_winding, patch2->emitter_skylevel #ifdef HLRAD_DIVERSE_LIGHTING , lighting_power, lighting_scale #endif ); vec_t frac; frac = dist / patch2->emitter_range; frac = (frac - 0.5f) * 2.0f; // make a smooth transition between the two methods frac = max (0, min (frac, 1)); trans_one = frac * trans_one + (1 - frac) * (sightarea / patch2->area); // because later we will multiply this back } #ifdef HLRAD_ACCURATEBOUNCE_ALTERNATEORIGIN else { if (light_behind_surface) { continue; } } #endif #endif #ifdef HLRAD_ACCURATEBOUNCE_REDUCEAREA trans_one *= patch2->exposure; #endif VectorFill(trans, trans_one); VectorMultiply(trans, transparency, trans); //hullu: add transparency effect #ifdef HLRAD_TRANSLUCENT if (patch->translucent_b) { if (useback) { for (int x = 0; x < 3; x++) { trans[x] = patch->translucent_v[x] * trans[x]; } } else { for (int x = 0; x < 3; x++) { trans[x] = (1 - patch->translucent_v[x]) * trans[x]; } } } #endif #ifdef HLRAD_RGBTRANSFIX #ifdef HLRAD_ACCURATEBOUNCE if (trans_one <= 0.0) { continue; } #else if (trans_one >= 0) #endif { #ifndef HLRAD_TRANSWEIRDFIX #ifdef HLRAD_NOSWAP send = trans_one * area; #else send = trans_one * patch2->area; #endif if (send > 0.4f) { #ifdef HLRAD_NOSWAP trans_one = 0.4f / area; #else trans_one = 0.4f / patch2->area; #endif send = 0.4f; VectorFill(trans, trans_one); VectorMultiply(trans, transparency, trans); } #endif /*HLRAD_TRANSWEIRDFIX*/ #ifndef HLRAD_TRANSNONORMALIZE total += send; #endif #else /*HLRAD_RGBTRANSFIX*/ #ifdef HLRAD_ACCURATEBOUNCE if (VectorAvg(trans) <= 0.0) { continue; } #else if (VectorAvg(trans) >= 0) #endif { /////////////////////////////////////////RED send = trans[0] * patch2->area; // Caps light from getting weird if (send > 0.4f) { trans[0] = 0.4f / patch2->area; send = 0.4f; } #ifndef HLRAD_TRANSNONORMALIZE total += send / 3.0f; #endif /////////////////////////////////////////GREEN send = trans[1] * patch2->area; // Caps light from getting weird if (send > 0.4f) { trans[1] = 0.4f / patch2->area; send = 0.4f; } #ifndef HLRAD_TRANSNONORMALIZE total += send / 3.0f; #endif /////////////////////////////////////////BLUE send = trans[2] * patch2->area; // Caps light from getting weird if (send > 0.4f) { trans[2] = 0.4f / patch2->area; send = 0.4f; } #ifndef HLRAD_TRANSNONORMALIZE total += send / 3.0f; #endif #endif /*HLRAD_RGBTRANSFIX*/ #ifdef HLRAD_TRANSFERDATA_COMPRESS VectorScale(trans, patch2 -> area, trans); #else // scale to 16 bit (black magic) #ifdef HLRAD_NOSWAP VectorScale(trans, patch2 -> area * INVERSE_TRANSFER_SCALE, trans); #else VectorScale(trans, area * INVERSE_TRANSFER_SCALE, trans); #endif /*HLRAD_NOSWAP*/ if (trans[0] >= TRANSFER_SCALE_MAX) { trans[0] = TRANSFER_SCALE_MAX; } if (trans[1] >= TRANSFER_SCALE_MAX) { trans[1] = TRANSFER_SCALE_MAX; } if (trans[2] >= TRANSFER_SCALE_MAX) { trans[2] = TRANSFER_SCALE_MAX; } #endif } #ifndef HLRAD_ACCURATEBOUNCE else { #if 0 Warning("transfer < 0 (%4.3f %4.3f %4.3f): dist=(%f)\n" " dot1=(%f) patch@(%4.3f %4.3f %4.3f) normal(%4.3f %4.3f %4.3f)\n" " dot2=(%f) patch@(%4.3f %4.3f %4.3f) normal(%4.3f %4.3f %4.3f)\n", trans[0], trans[1], trans[2], dist, dot1, patch->origin[0], patch->origin[1], patch->origin[2], patch->normal[0], patch->normal[1], patch->normal[2], dot2, patch2->origin[0], patch2->origin[1], patch2->origin[2], patch2->normal[0], patch2->normal[1], patch2->normal[2]); #endif VectorFill(trans,0.0); } #endif #ifdef HLRAD_TRANSFERDATA_COMPRESS VectorCopy(trans, tRGBData); *tIndex = j; tRGBData+=3; tIndex++; patch->iData++; #else VectorCopy(trans, *tRGBData); *tIndex = j; tRGBData++; tIndex++; patch->iData++; #endif count++; } // copy the transfers out if (patch->iData) { #ifdef HLRAD_TRANSFERDATA_COMPRESS unsigned data_size = patch->iData * vector_size[g_rgbtransfer_compress_type] + unused_size; #else unsigned data_size = patch->iData * sizeof(rgb_transfer_data_t); #endif patch->tRGBData = (rgb_transfer_data_t*)AllocBlock(data_size); patch->tIndex = CompressTransferIndicies(tIndex_All, patch->iData, &patch->iIndex); hlassume(patch->tRGBData != NULL, assume_NoMemory); hlassume(patch->tIndex != NULL, assume_NoMemory); ThreadLock(); g_transfer_data_bytes += data_size; ThreadUnlock(); #ifdef HLRAD_REFLECTIVITY total = 1 / Q_PI; #else #ifdef HLRAD_TRANSNONORMALIZE #ifdef HLRAD_TRANSTOTAL_HACK total = g_transtotal_hack / Q_PI; #else total = 0.5 / Q_PI; #endif #else // // normalize all transfers so exactly 50% of the light // is transfered to the surroundings // total = 0.5 / total; #endif #endif { #ifdef HLRAD_TRANSFERDATA_COMPRESS unsigned x; rgb_transfer_data_t* t1 = patch->tRGBData; float* t2 = tRGBData_All; float f[3]; for (x = 0; x < patch->iData; x++, t1+=vector_size[g_rgbtransfer_compress_type], t2+=3) { VectorScale( t2, total, f ); vector_compress (g_rgbtransfer_compress_type, t1, &f[0], &f[1], &f[2]); } #else unsigned x; rgb_transfer_data_t* t1 = patch->tRGBData; rgb_transfer_data_t* t2 = tRGBData_All; for (x = 0; x < patch->iData; x++, t1++, t2++) { VectorScale( *t2, total, *t1 ); } #endif } } } FreeBlock(tIndex_All); FreeBlock(tRGBData_All); ThreadLock(); g_total_transfer += count; ThreadUnlock(); } #ifdef SYSTEM_WIN32 #pragma warning(pop) #endif /* * ============= * SwapTransfersTask * * Change transfers from light sent out to light collected in. * In an ideal world, they would be exactly symetrical, but * because the form factors are only aproximated, then normalized, * they will actually be rather different. * ============= */ #ifndef HLRAD_NOSWAP void SwapRGBTransfers(const int patchnum) { patch_t* patch = &g_patches[patchnum]; transfer_index_t* tIndex = patch->tIndex; rgb_transfer_data_t* tRGBData= patch->tRGBData; unsigned x; for (x = 0; x < patch->iIndex; x++, tIndex++) { unsigned size = (tIndex->size + 1); unsigned patchnum2 = tIndex->index; unsigned y; for (y = 0; y < size; y++, tRGBData++, patchnum2++) { patch_t* patch2 = &g_patches[patchnum2]; if (patchnum2 > patchnum) { // done with this list return; } else if (!patch2->iData) { // Set to zero in this impossible case Log("patch2 has no iData\n"); VectorFill(*tRGBData, 0); continue; } else { transfer_index_t* tIndex2 = patch2->tIndex; rgb_transfer_data_t* tRGBData2 = patch2->tRGBData; int offset = FindTransferOffsetPatchnum(tIndex2, patch2, patchnum); if (offset >= 0) { rgb_transfer_data_t tmp; VectorCopy(*tRGBData, tmp) VectorCopy(tRGBData2[offset], *tRGBData); VectorCopy(tmp, tRGBData2[offset]); } else { // Set to zero in this impossible case Log("FindTransferOffsetPatchnum returned -1 looking for patch %d in patch %d's transfer lists\n", patchnum, patchnum2); VectorFill(*tRGBData, 0); return; } } } } }
// draws this grass particle //extern void RenderFog ( void ); // Fograin92: Disabled void CGrassParticle::Draw( void ) { if (m_bIngoreParticle == true) return; if(sParticle.pTexture == NULL) { CONPRINT("Null texture in particle\n"); return; } Vector vForward, vRight, vUp, vDir; AngleVectors(v_angles, vForward, vRight, vUp ); vDir = ( sParticle.vPosition - flPlayerOrigin ).Normalize( ); if ( DotProduct ( vDir, vForward ) < 0 ) return; int iHealth = 0; // lets make sure transparency doesn't overflow or udnerflow if (sParticle.iTransparency > 255) sParticle.iTransparency = 255; if (sParticle.iTransparency < 0) sParticle.iTransparency = 0; iHealth = sParticle.iTransparency; if (pSys->bLOD) // fade out particles that are further away (LOD) { float flDistance = sqrt(sParticle.flSquareDistanceToPlayer); if ((flDistance > m_flLodMinDistance) && (flDistance < m_flLodMaxDistance)) { float flTransparencyFactor = 1 - ((flDistance - m_flLodMinDistance) / (m_flLodMaxDistance - m_flLodMinDistance)); if (flTransparencyFactor > 1) flTransparencyFactor = 1; if (flTransparencyFactor < 0) flTransparencyFactor = 0; iHealth *= flTransparencyFactor; } } vec3_t vPoint, vPosition; vec3_t vWaveForward, vWaveRight, vWaveUp; // We again copy part->origin into another vector to prevent us accidentally messing with it VectorCopy( sParticle.vPosition, vPosition ); AngleVectors(m_vNormal, vForward, vRight, vUp); AngleVectors(m_vWaveNormal, vWaveForward, vWaveRight, vWaveUp); glColor4ub(sParticle.iRed, sParticle.iGreen, sParticle.iBlue,iHealth); //RenderFog(); // Fograin92: Disabled // Finally, we draw the particle glBindTexture(GL_TEXTURE_2D, sParticle.pTexture->iID); glBegin(GL_QUADS); glTexCoord2f(0, 0.95f); VectorMA (sParticle.vPosition, sParticle.flSize, vWaveUp, vPoint); VectorMA (vPoint, -sParticle.flSize, vWaveRight, vPoint); glVertex3fv(vPoint); glTexCoord2f(0.95f, 0.95f); VectorMA (sParticle.vPosition, sParticle.flSize, vWaveUp, vPoint); VectorMA (vPoint, sParticle.flSize, vWaveRight, vPoint); glVertex3fv(vPoint); glTexCoord2f(0.95f, 0); VectorMA (sParticle.vPosition, -sParticle.flSize, vUp, vPoint); VectorMA (vPoint, sParticle.flSize, vRight, vPoint); glVertex3fv(vPoint); glTexCoord2f(0, 0); VectorMA (sParticle.vPosition, -sParticle.flSize, vUp, vPoint); VectorMA (vPoint, -sParticle.flSize, vRight, vPoint); glVertex3fv(vPoint); glEnd(); }
void R_RecursiveClipBPoly (bedge_t *pedges, mnode_t *pnode, msurface_t *psurf) { bedge_t *psideedges[2], *pnextedge, *ptedge; int i, side, lastside; float dist, frac, lastdist; mplane_t *splitplane, tplane; mvertex_t *pvert, *plastvert, *ptvert; mnode_t *pn; psideedges[0] = psideedges[1] = NULL; makeclippededge = false; // transform the BSP plane into model space // FIXME: cache these? splitplane = pnode->plane; tplane.dist = -PlaneDiff(r_entorigin, splitplane); tplane.normal[0] = PlaneDist (entity_rotation[0], splitplane); tplane.normal[1] = PlaneDist (entity_rotation[1], splitplane); tplane.normal[2] = PlaneDist (entity_rotation[2], splitplane); // clip edges to BSP plane for ( ; pedges ; pedges = pnextedge) { pnextedge = pedges->pnext; // set the status for the last point as the previous point // FIXME: cache this stuff somehow? plastvert = pedges->v[0]; lastdist = DotProduct (plastvert->position, tplane.normal) - tplane.dist; lastside = (lastdist <= 0); pvert = pedges->v[1]; dist = DotProduct (pvert->position, tplane.normal) - tplane.dist; side = (dist <= 0); if (side != lastside) { // clipped if (numbverts >= MAX_BMODEL_VERTS) return; // generate the clipped vertex frac = lastdist / (lastdist - dist); ptvert = &pbverts[numbverts++]; ptvert->position[0] = plastvert->position[0] + frac * (pvert->position[0] - plastvert->position[0]); ptvert->position[1] = plastvert->position[1] + frac * (pvert->position[1] - plastvert->position[1]); ptvert->position[2] = plastvert->position[2] + frac * (pvert->position[2] - plastvert->position[2]); // split into two edges, one on each side, and remember entering // and exiting points // FIXME: share the clip edge by having a winding direction flag? if (numbedges >= (MAX_BMODEL_EDGES - 1)) { Com_Printf ("Out of edges for bmodel\n"); return; } ptedge = &pbedges[numbedges]; ptedge->pnext = psideedges[lastside]; psideedges[lastside] = ptedge; ptedge->v[0] = plastvert; ptedge->v[1] = ptvert; ptedge = &pbedges[numbedges + 1]; ptedge->pnext = psideedges[side]; psideedges[side] = ptedge; ptedge->v[0] = ptvert; ptedge->v[1] = pvert; numbedges += 2; if (side == 0) { // entering for front, exiting for back pfrontenter = ptvert; makeclippededge = true; } else { pfrontexit = ptvert; makeclippededge = true; } } else { // add the edge to the appropriate side pedges->pnext = psideedges[side]; psideedges[side] = pedges; } } // if anything was clipped, reconstitute and add the edges along the clip // plane to both sides (but in opposite directions) if (makeclippededge) { if (numbedges >= (MAX_BMODEL_EDGES - 2)) { Com_Printf ("Out of edges for bmodel\n"); return; } ptedge = &pbedges[numbedges]; ptedge->pnext = psideedges[0]; psideedges[0] = ptedge; ptedge->v[0] = pfrontexit; ptedge->v[1] = pfrontenter; ptedge = &pbedges[numbedges + 1]; ptedge->pnext = psideedges[1]; psideedges[1] = ptedge; ptedge->v[0] = pfrontenter; ptedge->v[1] = pfrontexit; numbedges += 2; } // draw or recurse further for (i = 0; i < 2; i++) { if (psideedges[i]) { // draw if we've reached a non-solid leaf, done if all that's left is a // solid leaf, and continue down the tree if it's not a leaf pn = pnode->children[i]; // we're done with this branch if the node or leaf isn't in the PVS if (pn->visframe == r_visframecount) { if (pn->contents < 0) { if (pn->contents != CONTENTS_SOLID) { r_currentbkey = ((mleaf_t *)pn)->key; R_RenderBmodelFace (psideedges[i], psurf); } } else { R_RecursiveClipBPoly (psideedges[i], pnode->children[i], psurf); } } } } }
/* ================= R_DrawAliasFrameLerp ================= */ void R_DrawAliasFrameLerp (maliasmodel_t *paliashdr, entity_t *e) { int i, j, k, meshnum; maliasframe_t *frame, *oldframe; maliasmesh_t mesh; maliasvertex_t *v, *ov; vec3_t move, delta, vectors[3]; vec3_t curScale, oldScale, curNormal, oldNormal; vec3_t tempNormalsArray[MD3_MAX_VERTS]; vec2_t tempSkinCoord; vec3_t meshlight, lightcolor; float alpha, meshalpha, thisalpha, shellscale, frontlerp, backlerp = e->backlerp; image_t *skin; renderparms_t skinParms; qboolean shellModel = e->flags & ( RF_SHELL_RED | RF_SHELL_GREEN | RF_SHELL_BLUE | RF_SHELL_DOUBLE | RF_SHELL_HALF_DAM); frontlerp = 1.0 - backlerp; if (e->flags & RF_TRANSLUCENT) alpha = e->alpha; else alpha = 1.0; frame = paliashdr->frames + e->frame; oldframe = paliashdr->frames + e->oldframe; VectorScale(frame->scale, frontlerp, curScale); VectorScale(oldframe->scale, backlerp, oldScale); // move should be the delta back to the previous frame * backlerp VectorSubtract (e->oldorigin, e->origin, delta); AngleVectors (e->angles, vectors[0], vectors[1], vectors[2]); move[0] = DotProduct (delta, vectors[0]); // forward move[1] = -DotProduct (delta, vectors[1]); // left move[2] = DotProduct (delta, vectors[2]); // up VectorAdd (move, oldframe->translate, move); for (i=0 ; i<3 ; i++) move[i] = backlerp*move[i] + frontlerp*frame->translate[i]; R_SetVertexOverbrights(true); R_SetShellBlend (true); // new outer loop for whole model for (k=0, meshnum=0; k < paliashdr->num_meshes; k++, meshnum++) { mesh = paliashdr->meshes[k]; skinParms = mesh.skins[e->skinnum].renderparms; // select skin if (e->skin) skin = e->skin; // custom player skin else skin = currentmodel->skins[k][e->skinnum]; if (!skin) skin = r_notexture; if ( !shellModel ) GL_Bind(skin->texnum); else if (FlowingShell()) alpha = 0.7; // md3 skin scripting if (skinParms.nodraw) continue; // skip this mesh for this skin if (skinParms.twosided) GL_Disable(GL_CULL_FACE); if (skinParms.alphatest && !shellModel) GL_Enable(GL_ALPHA_TEST); if (skinParms.fullbright) VectorSet(meshlight, 1.0f, 1.0f, 1.0f); else VectorCopy(shadelight, meshlight); meshalpha = alpha * skinParms.basealpha; if (meshalpha < 1.0f || skinParms.blend) GL_Enable (GL_BLEND); else GL_Disable (GL_BLEND); if (skinParms.blend && !shellModel) GL_BlendFunc (skinParms.blendfunc_src, skinParms.blendfunc_dst); else GL_BlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); // md3 skin scripting v = mesh.vertexes + e->frame*mesh.num_verts; ov = mesh.vertexes + e->oldframe*mesh.num_verts; rb_vertex = 0; for (i=0; i<mesh.num_verts; i++, v++, ov++) { // lerp verts curNormal[0] = r_sinTable[v->normal[0]] * r_cosTable[v->normal[1]]; curNormal[1] = r_sinTable[v->normal[0]] * r_sinTable[v->normal[1]]; curNormal[2] = r_cosTable[v->normal[0]]; oldNormal[0] = r_sinTable[ov->normal[0]] * r_cosTable[ov->normal[1]]; oldNormal[1] = r_sinTable[ov->normal[0]] * r_sinTable[ov->normal[1]]; oldNormal[2] = r_cosTable[ov->normal[0]]; VectorSet ( tempNormalsArray[i], curNormal[0] + (oldNormal[0] - curNormal[0])*backlerp, curNormal[1] + (oldNormal[1] - curNormal[1])*backlerp, curNormal[2] + (oldNormal[2] - curNormal[2])*backlerp ); if (shellModel) shellscale = (e->flags & RF_WEAPONMODEL) ? WEAPON_SHELL_SCALE: POWERSUIT_SCALE; else shellscale = 0.0; VectorSet ( tempVertexArray[meshnum][i], move[0] + ov->point[0]*oldScale[0] + v->point[0]*curScale[0] + tempNormalsArray[i][0]*shellscale, move[1] + ov->point[1]*oldScale[1] + v->point[1]*curScale[1] + tempNormalsArray[i][1]*shellscale, move[2] + ov->point[2]*oldScale[2] + v->point[2]*curScale[2] + tempNormalsArray[i][2]*shellscale ); // calc lighting and alpha if (shellModel) VectorCopy(meshlight, lightcolor); else R_LightAliasModel(meshlight, tempNormalsArray[i], lightcolor, v->lightnormalindex, !skinParms.nodiffuse); //thisalpha = R_CalcEntAlpha(meshalpha, tempVertexArray[meshnum][i]); thisalpha = meshalpha; // get tex coords if (shellModel && FlowingShell()) { tempSkinCoord[0] = (tempVertexArray[meshnum][i][0] + tempVertexArray[meshnum][i][1]) / 40.0 + shellFlowH; tempSkinCoord[1] = tempVertexArray[meshnum][i][2] / 40.0 + shellFlowV; } else { tempSkinCoord[0] = mesh.stcoords[i].st[0]; tempSkinCoord[1] = mesh.stcoords[i].st[1]; } // add to arrays VA_SetElem2(texCoordArray[0][rb_vertex], tempSkinCoord[0], tempSkinCoord[1]); VA_SetElem3(vertexArray[rb_vertex], tempVertexArray[meshnum][i][0], tempVertexArray[meshnum][i][1], tempVertexArray[meshnum][i][2]); VA_SetElem4(colorArray[rb_vertex], lightcolor[0], lightcolor[1], lightcolor[2], thisalpha); rb_vertex++; } if (!shellModel) RB_ModifyTextureCoords (&texCoordArray[0][0][0], &vertexArray[0][0], rb_vertex, skinParms); // set indices for each triangle and draw rb_index = 0; for (j=0; j < mesh.num_tris; j++) { indexArray[rb_index++] = mesh.indexes[3*j+0]; indexArray[rb_index++] = mesh.indexes[3*j+1]; indexArray[rb_index++] = mesh.indexes[3*j+2]; } RB_DrawArrays (GL_TRIANGLES); // glow pass if (mesh.skins[e->skinnum].glowimage && !shellModel) { float glowcolor; if (skinParms.glow.type > -1) glowcolor = RB_CalcGlowColor (skinParms); else glowcolor = 1.0; qglDisableClientState (GL_COLOR_ARRAY); qglColor4f(glowcolor, glowcolor, glowcolor, 1.0); GL_Enable (GL_BLEND); GL_BlendFunc (GL_ONE, GL_ONE); GL_Bind(mesh.skins[e->skinnum].glowimage->texnum); RB_DrawArrays (GL_TRIANGLES); qglEnableClientState (GL_COLOR_ARRAY); qglColor4f(1.0, 1.0, 1.0, 1.0); } // envmap pass if (skinParms.envmap > 0.0f && !shellModel) { GL_Enable (GL_BLEND); GL_BlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); qglTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_SPHERE_MAP); qglTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_SPHERE_MAP); // apply alpha to array for (i=0; i<mesh.num_verts; i++) //colorArray[i][3] = R_CalcEntAlpha(meshalpha*skinParms.envmap, tempVertexArray[meshnum][i]); colorArray[i][3] = meshalpha*skinParms.envmap; GL_Bind(r_envmappic->texnum); qglEnable(GL_TEXTURE_GEN_S); qglEnable(GL_TEXTURE_GEN_T); RB_DrawArrays (GL_TRIANGLES); qglDisable(GL_TEXTURE_GEN_S); qglDisable(GL_TEXTURE_GEN_T); } RB_DrawMeshTris (GL_TRIANGLES, 1); // md3 skin scripting if (skinParms.twosided) GL_Enable(GL_CULL_FACE); if (skinParms.alphatest && !shellModel) GL_Disable(GL_ALPHA_TEST); GL_Disable (GL_BLEND); // md3 skin scripting } // end new outer loop R_SetShellBlend (false); R_SetVertexOverbrights(false); }
/* ================= RB_BeginDrawingView Any mirrored or portaled views have already been drawn, so prepare to actually render the visible surfaces for this view ================= */ void RB_BeginDrawingView (void) { int clearBits = 0; // sync with gl if needed if ( r_finish->integer == 1 && !glState.finishCalled ) { qglFinish (); glState.finishCalled = qtrue; } if ( r_finish->integer == 0 ) { glState.finishCalled = qtrue; } // we will need to change the projection matrix before drawing // 2D images again backEnd.projection2D = qfalse; // // set the modelview matrix for the viewer // SetViewportAndScissor(); // ensures that depth writes are enabled for the depth clear GL_State( GLS_DEFAULT ); // clear relevant buffers clearBits = GL_DEPTH_BUFFER_BIT; if ( r_measureOverdraw->integer || r_shadows->integer == 2 ) { clearBits |= GL_STENCIL_BUFFER_BIT; } if ( r_fastsky->integer && !( backEnd.refdef.rdflags & RDF_NOWORLDMODEL ) ) { clearBits |= GL_COLOR_BUFFER_BIT; // FIXME: only if sky shaders have been used #ifdef _DEBUG qglClearColor( 0.8f, 0.7f, 0.4f, 1.0f ); // FIXME: get color of sky #else qglClearColor( 0.0f, 0.0f, 0.0f, 1.0f ); // FIXME: get color of sky #endif } qglClear( clearBits ); if ( ( backEnd.refdef.rdflags & RDF_HYPERSPACE ) ) { RB_Hyperspace(); return; } else { backEnd.isHyperspace = qfalse; } glState.faceCulling = -1; // force face culling to set next time // we will only draw a sun if there was sky rendered in this view backEnd.skyRenderedThisView = qfalse; // clip to the plane of the portal if ( backEnd.viewParms.isPortal ) { float plane[4]; #ifdef IOS float plane2[4]; #else double plane2[4]; #endif // IOS plane[0] = backEnd.viewParms.portalPlane.normal[0]; plane[1] = backEnd.viewParms.portalPlane.normal[1]; plane[2] = backEnd.viewParms.portalPlane.normal[2]; plane[3] = backEnd.viewParms.portalPlane.dist; plane2[0] = DotProduct (backEnd.viewParms.or.axis[0], plane); plane2[1] = DotProduct (backEnd.viewParms.or.axis[1], plane); plane2[2] = DotProduct (backEnd.viewParms.or.axis[2], plane); plane2[3] = DotProduct (plane, backEnd.viewParms.or.origin) - plane[3]; qglLoadMatrixf( s_flipMatrix ); qglClipPlane (GL_CLIP_PLANE0, plane2); qglEnable (GL_CLIP_PLANE0); } else { qglDisable (GL_CLIP_PLANE0); } }
float ShortestLineSegBewteen2LineSegs( vec3_t start1, vec3_t end1, vec3_t start2, vec3_t end2, vec3_t close_pnt1, vec3_t close_pnt2 ) { float current_dist, new_dist; vec3_t new_pnt; //start1, end1 : the first segment //start2, end2 : the second segment //output, one point on each segment, the closest two points on the segments. //compute some temporaries: //vec start_dif = start2 - start1 vec3_t start_dif; VectorSubtract( start2, start1, start_dif ); //vec v1 = end1 - start1 vec3_t v1; VectorSubtract( end1, start1, v1 ); //vec v2 = end2 - start2 vec3_t v2; VectorSubtract( end2, start2, v2 ); // float v1v1 = DotProduct( v1, v1 ); float v2v2 = DotProduct( v2, v2 ); float v1v2 = DotProduct( v1, v2 ); //the main computation float denom = (v1v2 * v1v2) - (v1v1 * v2v2); //if denom is small, then skip all this and jump to the section marked below if ( fabs(denom) > 0.001f ) { float s = -( (v2v2*DotProduct( v1, start_dif )) - (v1v2*DotProduct( v2, start_dif )) ) / denom; float t = ( (v1v1*DotProduct( v2, start_dif )) - (v1v2*DotProduct( v1, start_dif )) ) / denom; qboolean done = qtrue; if ( s < 0 ) { done = qfalse; s = 0;// and see note below } if ( s > 1 ) { done = qfalse; s = 1;// and see note below } if ( t < 0 ) { done = qfalse; t = 0;// and see note below } if ( t > 1 ) { done = qfalse; t = 1;// and see note below } //vec close_pnt1 = start1 + s * v1 VectorMA( start1, s, v1, close_pnt1 ); //vec close_pnt2 = start2 + t * v2 VectorMA( start2, t, v2, close_pnt2 ); current_dist = Distance( close_pnt1, close_pnt2 ); //now, if none of those if's fired, you are done. if ( done ) { return current_dist; } //If they did fire, then we need to do some additional tests. //What we are gonna do is see if we can find a shorter distance than the above //involving the endpoints. } else { //******start here for paralell lines with current_dist = infinity**** current_dist = Q3_INFINITE; } //test 2 close_pnts first /* G_FindClosestPointOnLineSegment( start1, end1, close_pnt2, new_pnt ); new_dist = Distance( close_pnt2, new_pnt ); if ( new_dist < current_dist ) {//then update close_pnt1 close_pnt2 and current_dist VectorCopy( new_pnt, close_pnt1 ); VectorCopy( close_pnt2, close_pnt2 ); current_dist = new_dist; } G_FindClosestPointOnLineSegment( start2, end2, close_pnt1, new_pnt ); new_dist = Distance( close_pnt1, new_pnt ); if ( new_dist < current_dist ) {//then update close_pnt1 close_pnt2 and current_dist VectorCopy( close_pnt1, close_pnt1 ); VectorCopy( new_pnt, close_pnt2 ); current_dist = new_dist; } */ //test all the endpoints new_dist = Distance( start1, start2 ); if ( new_dist < current_dist ) {//then update close_pnt1 close_pnt2 and current_dist VectorCopy( start1, close_pnt1 ); VectorCopy( start2, close_pnt2 ); current_dist = new_dist; } new_dist = Distance( start1, end2 ); if ( new_dist < current_dist ) {//then update close_pnt1 close_pnt2 and current_dist VectorCopy( start1, close_pnt1 ); VectorCopy( end2, close_pnt2 ); current_dist = new_dist; } new_dist = Distance( end1, start2 ); if ( new_dist < current_dist ) {//then update close_pnt1 close_pnt2 and current_dist VectorCopy( end1, close_pnt1 ); VectorCopy( start2, close_pnt2 ); current_dist = new_dist; } new_dist = Distance( end1, end2 ); if ( new_dist < current_dist ) {//then update close_pnt1 close_pnt2 and current_dist VectorCopy( end1, close_pnt1 ); VectorCopy( end2, close_pnt2 ); current_dist = new_dist; } //Then we have 4 more point / segment tests G_FindClosestPointOnLineSegment( start2, end2, start1, new_pnt ); new_dist = Distance( start1, new_pnt ); if ( new_dist < current_dist ) {//then update close_pnt1 close_pnt2 and current_dist VectorCopy( start1, close_pnt1 ); VectorCopy( new_pnt, close_pnt2 ); current_dist = new_dist; } G_FindClosestPointOnLineSegment( start2, end2, end1, new_pnt ); new_dist = Distance( end1, new_pnt ); if ( new_dist < current_dist ) {//then update close_pnt1 close_pnt2 and current_dist VectorCopy( end1, close_pnt1 ); VectorCopy( new_pnt, close_pnt2 ); current_dist = new_dist; } G_FindClosestPointOnLineSegment( start1, end1, start2, new_pnt ); new_dist = Distance( start2, new_pnt ); if ( new_dist < current_dist ) {//then update close_pnt1 close_pnt2 and current_dist VectorCopy( new_pnt, close_pnt1 ); VectorCopy( start2, close_pnt2 ); current_dist = new_dist; } G_FindClosestPointOnLineSegment( start1, end1, end2, new_pnt ); new_dist = Distance( end2, new_pnt ); if ( new_dist < current_dist ) {//then update close_pnt1 close_pnt2 and current_dist VectorCopy( new_pnt, close_pnt1 ); VectorCopy( end2, close_pnt2 ); current_dist = new_dist; } return current_dist; }
/* ================= R_CullAliasModel ================= */ static qboolean R_CullAliasModel ( vec3_t bbox[8], entity_t *e ) { int i, j; vec3_t mins, maxs, tmp; //angles; vec3_t vectors[3]; maliasmodel_t *paliashdr; maliasframe_t *pframe, *poldframe; int mask, aggregatemask = ~0; paliashdr = (maliasmodel_t *)currentmodel->extradata; if ( ( e->frame >= paliashdr->num_frames ) || ( e->frame < 0 ) ) { VID_Printf (PRINT_ALL, "R_CullAliasModel %s: no such frame %d\n", currentmodel->name, e->frame); e->frame = 0; } if ( ( e->oldframe >= paliashdr->num_frames ) || ( e->oldframe < 0 ) ) { VID_Printf (PRINT_ALL, "R_CullAliasModel %s: no such oldframe %d\n", currentmodel->name, e->oldframe); e->oldframe = 0; } pframe = paliashdr->frames + e->frame; poldframe = paliashdr->frames + e->oldframe; // compute axially aligned mins and maxs if ( pframe == poldframe ) { VectorCopy(pframe->mins, mins); VectorCopy(pframe->maxs, maxs); } else { for ( i = 0; i < 3; i++ ) { if (pframe->mins[i] < poldframe->mins[i]) mins[i] = pframe->mins[i]; else mins[i] = poldframe->mins[i]; if (pframe->maxs[i] > poldframe->maxs[i]) maxs[i] = pframe->maxs[i]; else maxs[i] = poldframe->maxs[i]; } } // jitspoe's bbox rotation fix // compute and rotate bonding box e->angles[ROLL] = -e->angles[ROLL]; // roll is backwards AngleVectors(e->angles, vectors[0], vectors[1], vectors[2]); e->angles[ROLL] = -e->angles[ROLL]; // roll is backwards VectorSubtract(vec3_origin, vectors[1], vectors[1]); // AngleVectors returns "right" instead of "left" for (i = 0; i < 8; i++) { tmp[0] = ((i & 1) ? mins[0] : maxs[0]); tmp[1] = ((i & 2) ? mins[1] : maxs[1]); tmp[2] = ((i & 4) ? mins[2] : maxs[2]); bbox[i][0] = vectors[0][0] * tmp[0] + vectors[1][0] * tmp[1] + vectors[2][0] * tmp[2] + e->origin[0]; bbox[i][1] = vectors[0][1] * tmp[0] + vectors[1][1] * tmp[1] + vectors[2][1] * tmp[2] + e->origin[1]; bbox[i][2] = vectors[0][2] * tmp[0] + vectors[1][2] * tmp[1] + vectors[2][2] * tmp[2] + e->origin[2]; } // cull for (i=0; i<8; i++) { mask = 0; for (j=0; j<4; j++) { float dp = DotProduct(frustum[j].normal, bbox[i]); if ( ( dp - frustum[j].dist ) < 0 ) mask |= (1<<j); } aggregatemask &= mask; } if ( aggregatemask ) return true; return false; }
//----------------------------------------------------------------------------- // Purpose: Do the headlight //----------------------------------------------------------------------------- void CFlashlightEffect::UpdateLightNew(const Vector &vecPos, const Vector &vecForward, const Vector &vecRight, const Vector &vecUp) { VPROF_BUDGET("CFlashlightEffect::UpdateLightNew", VPROF_BUDGETGROUP_SHADOW_DEPTH_TEXTURING); FlashlightState_t state; // We will lock some of the flashlight params if player is on a ladder, to prevent oscillations due to the trace-rays bool bPlayerOnLadder = (C_BasePlayer::GetLocalPlayer()->GetMoveType() == MOVETYPE_LADDER); const float flEpsilon = 0.1f; // Offset flashlight position along vecUp const float flDistCutoff = 128.0f; const float flDistDrag = 0.2; CTraceFilterSkipPlayerAndViewModel traceFilter; float flOffsetY = r_flashlightoffsety.GetFloat(); if (r_swingflashlight.GetBool()) { // This projects the view direction backwards, attempting to raise the vertical // offset of the flashlight, but only when the player is looking down. Vector vecSwingLight = vecPos + vecForward * -12.0f; if (vecSwingLight.z > vecPos.z) { flOffsetY += (vecSwingLight.z - vecPos.z); } } Vector vOrigin = vecPos + flOffsetY * vecUp; // Not on ladder...trace a hull if (!bPlayerOnLadder) { trace_t pmOriginTrace; UTIL_TraceHull(vecPos, vOrigin, Vector(-4, -4, -4), Vector(4, 4, 4), MASK_SOLID & ~(CONTENTS_HITBOX), &traceFilter, &pmOriginTrace); if (pmOriginTrace.DidHit()) { vOrigin = vecPos; } } else // on ladder...skip the above hull trace { vOrigin = vecPos; } // Now do a trace along the flashlight direction to ensure there is nothing within range to pull back from int iMask = MASK_OPAQUE_AND_NPCS; iMask &= ~CONTENTS_HITBOX; iMask |= CONTENTS_WINDOW; Vector vTarget = vecPos + vecForward * r_flashlightfar.GetFloat(); // Work with these local copies of the basis for the rest of the function Vector vDir = vTarget - vOrigin; Vector vRight = vecRight; Vector vUp = vecUp; VectorNormalize(vDir); VectorNormalize(vRight); VectorNormalize(vUp); // Orthonormalize the basis, since the flashlight texture projection will require this later... vUp -= DotProduct(vDir, vUp) * vDir; VectorNormalize(vUp); vRight -= DotProduct(vDir, vRight) * vDir; VectorNormalize(vRight); vRight -= DotProduct(vUp, vRight) * vUp; VectorNormalize(vRight); AssertFloatEquals(DotProduct(vDir, vRight), 0.0f, 1e-3); AssertFloatEquals(DotProduct(vDir, vUp), 0.0f, 1e-3); AssertFloatEquals(DotProduct(vRight, vUp), 0.0f, 1e-3); trace_t pmDirectionTrace; UTIL_TraceHull(vOrigin, vTarget, Vector(-4, -4, -4), Vector(4, 4, 4), iMask, &traceFilter, &pmDirectionTrace); if (r_flashlightvisualizetrace.GetBool() == true) { debugoverlay->AddBoxOverlay(pmDirectionTrace.endpos, Vector(-4, -4, -4), Vector(4, 4, 4), QAngle(0, 0, 0), 0, 0, 255, 16, 0); debugoverlay->AddLineOverlay(vOrigin, pmDirectionTrace.endpos, 255, 0, 0, false, 0); } float flDist = (pmDirectionTrace.endpos - vOrigin).Length(); if (flDist < flDistCutoff) { // We have an intersection with our cutoff range // Determine how far to pull back, then trace to see if we are clear float flPullBackDist = bPlayerOnLadder ? r_flashlightladderdist.GetFloat() : flDistCutoff - flDist; // Fixed pull-back distance if on ladder m_flDistMod = Lerp(flDistDrag, m_flDistMod, flPullBackDist); if (!bPlayerOnLadder) { trace_t pmBackTrace; UTIL_TraceHull(vOrigin, vOrigin - vDir*(flPullBackDist - flEpsilon), Vector(-4, -4, -4), Vector(4, 4, 4), iMask, &traceFilter, &pmBackTrace); if (pmBackTrace.DidHit()) { // We have an intersection behind us as well, so limit our m_flDistMod float flMaxDist = (pmBackTrace.endpos - vOrigin).Length() - flEpsilon; if (m_flDistMod > flMaxDist) m_flDistMod = flMaxDist; } } } else { m_flDistMod = Lerp(flDistDrag, m_flDistMod, 0.0f); } vOrigin = vOrigin - vDir * m_flDistMod; state.m_vecLightOrigin = vOrigin; BasisToQuaternion(vDir, vRight, vUp, state.m_quatOrientation); state.m_fQuadraticAtten = r_flashlightquadratic.GetFloat(); state.m_fLinearAtten = r_flashlightlinear.GetFloat(); state.m_fHorizontalFOVDegrees = r_flashlightfov.GetFloat(); state.m_fVerticalFOVDegrees = r_flashlightfov.GetFloat(); state.m_fConstantAtten = r_flashlightconstant.GetFloat(); state.m_Color[0] = 1.0f; state.m_Color[1] = 1.0f; state.m_Color[2] = 1.0f; state.m_Color[3] = r_flashlightambient.GetFloat(); state.m_NearZ = r_flashlightnear.GetFloat() + m_flDistMod; // Push near plane out so that we don't clip the world when the flashlight pulls back state.m_FarZ = r_flashlightfar.GetFloat(); state.m_bEnableShadows = r_flashlightdepthtexture.GetBool(); state.m_flShadowMapResolution = r_flashlightdepthres.GetInt(); state.m_pSpotlightTexture = m_FlashlightTexture; state.m_nSpotlightTextureFrame = 0; state.m_flShadowAtten = r_flashlightshadowatten.GetFloat(); state.m_flShadowSlopeScaleDepthBias = mat_slopescaledepthbias_shadowmap.GetFloat(); state.m_flShadowDepthBias = mat_depthbias_shadowmap.GetFloat(); if( m_FlashlightHandle == CLIENTSHADOW_INVALID_HANDLE ) { m_FlashlightHandle = g_pClientShadowMgr->CreateFlashlight( state ); } else { if( !r_flashlightlockposition.GetBool() ) { g_pClientShadowMgr->UpdateFlashlightState( m_FlashlightHandle, state ); } } g_pClientShadowMgr->UpdateProjectedTexture( m_FlashlightHandle, true ); // Kill the old flashlight method if we have one. LightOffOld(); #ifndef NO_TOOLFRAMEWORK if ( clienttools->IsInRecordingMode() ) { KeyValues *msg = new KeyValues( "FlashlightState" ); msg->SetFloat( "time", gpGlobals->curtime ); msg->SetInt( "entindex", m_nEntIndex ); msg->SetInt( "flashlightHandle", m_FlashlightHandle ); msg->SetPtr( "flashlightState", &state ); ToolFramework_PostToolMessage( HTOOLHANDLE_INVALID, msg ); msg->deleteThis(); } #endif }
/* ============== CG_DamageFeedback ============== */ void CG_DamageFeedback( int yawByte, int pitchByte, int damage ) { float left, front, up; float kick; int health; float scale; vec3_t dir; vec3_t angles; float dist; float yaw, pitch; //FIXME: Based on MOD, do different kinds of damage effects, // for example, Borg damage could progressively tint screen green and raise FOV? // the lower on health you are, the greater the view kick will be health = cg.snap->ps.stats[STAT_HEALTH]; if ( health < 40 ) { scale = 1; } else { scale = 40.0 / health; } kick = damage * scale; if (kick < 5) kick = 5; if (kick > 10) kick = 10; // if yaw and pitch are both 255, make the damage always centered (falling, etc) if ( yawByte == 255 && pitchByte == 255 ) { cg.damageX = 0; cg.damageY = 0; cg.v_dmg_roll = 0; cg.v_dmg_pitch = -kick; } else { // positional pitch = pitchByte / 255.0 * 360; yaw = yawByte / 255.0 * 360; angles[PITCH] = pitch; angles[YAW] = yaw; angles[ROLL] = 0; AngleVectors( angles, dir, NULL, NULL ); VectorSubtract( vec3_origin, dir, dir ); front = DotProduct (dir, cg.refdef.viewaxis[0] ); left = DotProduct (dir, cg.refdef.viewaxis[1] ); up = DotProduct (dir, cg.refdef.viewaxis[2] ); dir[0] = front; dir[1] = left; dir[2] = 0; dist = VectorLength( dir ); if ( dist < 0.1 ) { dist = 0.1f; } cg.v_dmg_roll = kick * left; cg.v_dmg_pitch = -kick * front; if ( front <= 0.1 ) { front = 0.1f; } cg.damageX = -left / front; cg.damageY = up / dist; } // clamp the position if ( cg.damageX > 1.0 ) { cg.damageX = 1.0; } if ( cg.damageX < - 1.0 ) { cg.damageX = -1.0; } if ( cg.damageY > 1.0 ) { cg.damageY = 1.0; } if ( cg.damageY < - 1.0 ) { cg.damageY = -1.0; } // don't let the screen flashes vary as much if ( kick > 10 ) { kick = 10; } cg.damageValue = kick; cg.v_dmg_time = cg.time + DAMAGE_TIME; cg.damageTime = cg.snap->serverTime; }
void R_MeshQueue_BeginScene(void) { mqt_count = 0; mqt_viewplanedist = DotProduct(r_refdef.view.origin, r_refdef.view.forward); mqt_viewmaxdist = 0; }
/* * AI_AddNode_Door * Drop a node at each side of the door * and force them to link. Only typical * doors are covered. */ static int AI_AddNode_Door( edict_t *ent ) { edict_t *other; vec3_t mins, maxs; vec3_t door_origin, movedir, moveangles; vec3_t moveaxis[3]; vec3_t MOVEDIR_UP = { 0, 0, 1 }; float nodeOffset = NODE_DENSITY * 0.75f; int i, j; int dropped[4]; if( ent->flags & FL_TEAMSLAVE ) return NODE_INVALID; // only team master will drop the nodes for( i = 0; i < 4; i++ ) dropped[i] = NODE_INVALID; //make box formed by all team members boxes VectorCopy( ent->r.absmin, mins ); VectorCopy( ent->r.absmax, maxs ); for( other = ent->teamchain; other; other = other->teamchain ) { AddPointToBounds( other->r.absmin, mins, maxs ); AddPointToBounds( other->r.absmax, mins, maxs ); } for( i = 0; i < 3; i++ ) door_origin[i] = ( maxs[i] + mins[i] ) * 0.5; VectorSubtract( ent->moveinfo.end_origin, ent->moveinfo.start_origin, movedir ); VectorNormalizeFast( movedir ); VecToAngles( movedir, moveangles ); AnglesToAxis( moveangles, moveaxis ); //add nodes in "side" direction nodes[nav.num_nodes].flags = 0; VectorMA( door_origin, nodeOffset, moveaxis[1], nodes[nav.num_nodes].origin ); #ifdef SHOW_JUMPAD_GUESS AI_JumpadGuess_ShowPoint( nodes[nav.num_nodes].origin, PATH_AMMO_BOX_MODEL ); #endif if( AI_DropNodeOriginToFloor( nodes[nav.num_nodes].origin, NULL ) ) { nodes[nav.num_nodes].flags |= AI_FlagsForNode( nodes[nav.num_nodes].origin, NULL ); dropped[0] = nav.num_nodes; nav.num_nodes++; } nodes[nav.num_nodes].flags = 0; VectorMA( door_origin, -nodeOffset, moveaxis[1], nodes[nav.num_nodes].origin ); #ifdef SHOW_JUMPAD_GUESS AI_JumpadGuess_ShowPoint( nodes[nav.num_nodes].origin, PATH_AMMO_BOX_MODEL ); #endif if( AI_DropNodeOriginToFloor( nodes[nav.num_nodes].origin, NULL ) ) { nodes[nav.num_nodes].flags |= AI_FlagsForNode( nodes[nav.num_nodes].origin, NULL ); dropped[1] = nav.num_nodes; nav.num_nodes++; } // if moving in the Y axis drop also in the other crossing direction and hope the // bad ones are inhibited by a solid if( DotProduct( MOVEDIR_UP, moveaxis[0] ) > 0.8 || DotProduct( MOVEDIR_UP, moveaxis[0] ) < -0.8 ) { nodes[nav.num_nodes].flags = 0; VectorMA( door_origin, nodeOffset, moveaxis[2], nodes[nav.num_nodes].origin ); #ifdef SHOW_JUMPAD_GUESS AI_JumpadGuess_ShowPoint( nodes[nav.num_nodes].origin, PATH_AMMO_BOX_MODEL ); #endif if( AI_DropNodeOriginToFloor( nodes[nav.num_nodes].origin, NULL ) ) { nodes[nav.num_nodes].flags |= AI_FlagsForNode( nodes[nav.num_nodes].origin, NULL ); dropped[2] = nav.num_nodes; nav.num_nodes++; } nodes[nav.num_nodes].flags = 0; VectorMA( door_origin, -nodeOffset, moveaxis[2], nodes[nav.num_nodes].origin ); #ifdef SHOW_JUMPAD_GUESS AI_JumpadGuess_ShowPoint( nodes[nav.num_nodes].origin, PATH_AMMO_BOX_MODEL ); #endif if( AI_DropNodeOriginToFloor( nodes[nav.num_nodes].origin, NULL ) ) { nodes[nav.num_nodes].flags |= AI_FlagsForNode( nodes[nav.num_nodes].origin, NULL ); dropped[3] = nav.num_nodes; nav.num_nodes++; } } // link those we dropped for( i = 0; i < 4; i++ ) { if( dropped[i] == NODE_INVALID ) continue; //put into ents table nav.navigableEnts[nav.num_navigableEnts].ent = ent; nav.navigableEnts[nav.num_navigableEnts].node = dropped[i]; nav.num_navigableEnts++; for( j = 0; j < 4; j++ ) { if( dropped[j] == NODE_INVALID ) continue; AI_AddLink( dropped[i], dropped[j], LINK_MOVE|LINK_DOOR ); } } return nav.num_nodes-1; }
/* ================== RB_AddFlare This is called at surface tesselation time ================== */ void RB_AddFlare( void *surface, int fogNum, vec3_t point, vec3_t color, vec3_t normal ) { int i; flare_t *f, *oldest; vec3_t local; float d; vec4_t eye, clip, normalized, window; backEnd.pc.c_flareAdds++; // if the point is off the screen, don't bother adding it // calculate screen coordinates and depth R_TransformModelToClip( point, backEnd.or.modelMatrix, backEnd.viewParms.projectionMatrix, eye, clip ); // check to see if the point is completely off screen for ( i = 0 ; i < 3 ; i++ ) { if ( clip[i] >= clip[3] || clip[i] <= -clip[3] ) { return; } } R_TransformClipToWindow( clip, &backEnd.viewParms, normalized, window ); if ( window[0] < 0 || window[0] >= backEnd.viewParms.viewportWidth || window[1] < 0 || window[1] >= backEnd.viewParms.viewportHeight ) { return; // shouldn't happen, since we check the clip[] above, except for FP rounding } // see if a flare with a matching surface, scene, and view exists oldest = r_flareStructs; for ( f = r_activeFlares ; f ; f = f->next ) { if ( f->surface == surface && f->frameSceneNum == backEnd.viewParms.frameSceneNum && f->inPortal == backEnd.viewParms.isPortal ) { break; } } // allocate a new one if (!f ) { if ( !r_inactiveFlares ) { // the list is completely full return; } f = r_inactiveFlares; r_inactiveFlares = r_inactiveFlares->next; f->next = r_activeFlares; r_activeFlares = f; f->surface = surface; f->frameSceneNum = backEnd.viewParms.frameSceneNum; f->inPortal = backEnd.viewParms.isPortal; f->addedFrame = -1; } if ( f->addedFrame != backEnd.viewParms.frameCount - 1 ) { f->visible = qfalse; f->fadeTime = backEnd.refdef.time - 2000; } f->addedFrame = backEnd.viewParms.frameCount; f->fogNum = fogNum; VectorCopy( color, f->color ); // fade the intensity of the flare down as the // light surface turns away from the viewer if ( normal ) { VectorSubtract( backEnd.viewParms.or.origin, point, local ); VectorNormalizeFast( local ); d = DotProduct( local, normal ); VectorScale( f->color, d, f->color ); } // save info needed to test f->windowX = backEnd.viewParms.viewportX + window[0]; f->windowY = backEnd.viewParms.viewportY + window[1]; f->eyeZ = eye[2]; }
/* ================ ClipSkyPolygon ================ */ static void ClipSkyPolygon (int nump, vec3_t vecs, int stage) { float *norm; float *v; qboolean front, back; float d, e; float dists[MAX_CLIP_VERTS]; int sides[MAX_CLIP_VERTS]; vec3_t newv[2][MAX_CLIP_VERTS]; int newc[2]; int i, j; if (nump > MAX_CLIP_VERTS-2) Com_Error (ERR_DROP, "ClipSkyPolygon: MAX_CLIP_VERTS"); if (stage == 6) { // fully clipped, so draw it AddSkyPolygon (nump, vecs); return; } front = back = qfalse; norm = sky_clip[stage]; for (i=0, v = vecs ; i<nump ; i++, v+=3) { d = DotProduct (v, norm); if (d > ON_EPSILON) { front = qtrue; sides[i] = SIDE_FRONT; } else if (d < -ON_EPSILON) { back = qtrue; sides[i] = SIDE_BACK; } else sides[i] = SIDE_ON; dists[i] = d; } if (!front || !back) { // not clipped ClipSkyPolygon (nump, vecs, stage+1); return; } // clip it sides[i] = sides[0]; dists[i] = dists[0]; VectorCopy (vecs, (vecs+(i*3)) ); newc[0] = newc[1] = 0; for (i=0, v = vecs ; i<nump ; i++, v+=3) { switch (sides[i]) { case SIDE_FRONT: VectorCopy (v, newv[0][newc[0]]); newc[0]++; break; case SIDE_BACK: VectorCopy (v, newv[1][newc[1]]); newc[1]++; break; case SIDE_ON: VectorCopy (v, newv[0][newc[0]]); newc[0]++; VectorCopy (v, newv[1][newc[1]]); newc[1]++; break; } if (sides[i] == SIDE_ON || sides[i+1] == SIDE_ON || sides[i+1] == sides[i]) continue; d = dists[i] / (dists[i] - dists[i+1]); for (j=0 ; j<3 ; j++) { e = v[j] + d*(v[j+3] - v[j]); newv[0][newc[0]][j] = e; newv[1][newc[1]][j] = e; } newc[0]++; newc[1]++; } // continue ClipSkyPolygon (newc[0], newv[0][0], stage+1); ClipSkyPolygon (newc[1], newv[1][0], stage+1); }
float Light::Geometric(Vector n, Vector l, Vector v) { Vector m; float G; if (Norm(l + v) == 0) { G = 1.0f; return G; } Vector h = (l + v) / Norm(l + v); Vector n0 = (l * DotProduct(n, l)) + (v * DotProduct(n, v)) - (l * (DotProduct(v, l) * DotProduct(v, n))) - (v * (DotProduct(v, l) * DotProduct(l, n))); if (Norm(n0) != 0) { m = n0 / Norm(n0); } else { m = h; } Vector hp = (m * (2 * DotProduct(m, h))) - h; if ((DotProduct(v, hp) >= 0) || (DotProduct(m, v) >= DotProduct(m, l))) { G = 1.0f; } else if ((DotProduct(v, hp) < 0) && (DotProduct(l, hp) >= 0)) { G = (2 * DotProduct(m, h) * DotProduct(m, v)) / DotProduct(h, v); } else { G = DotProduct(m, v) / DotProduct(m, l); } return G; }
int main(void) { //assign X component vec1[0] = 2.0; //assign Y component vec1[1] = 2.0; //assign Z component vec1[2] = 2.0; vec2[0] = 5.0; vec2[1] = 5.0; vec2[2] = 5.0; VectorAdd(vec1,vec2,vec3); printf("Vector addition: "); int i; for(i = 0; i < 3; i++) { printf("%g ", vec3[i]); } VectorSubtract(vec1,vec2,vec3); printf("\nVector subtraction: "); for(i = 0; i < sizeof(vec3)/sizeof(int); i++) { printf("%g ", vec3[i]); } DotProduct(vec1,vec2,cheez); printf("\nDot product: %g", cheez); Scaling(vec1, 2); printf("\nScaling by 2: "); for(i = 0; i < sizeof(vec1)/sizeof(int); i++) { printf("%g ", vec1[i]); } VCopy(vec1, vec3); printf("\nCopying vec1 to vec3: "); for(i = 0; i < sizeof(vec3)/sizeof(int); i++) { printf("%g ", vec3[i]); } VClear(vec3); printf("\nClearing vec3: "); for(i = 0; i < sizeof(vec3)/sizeof(int); i++) { printf("%g ", vec3[i]); } Inverse(vec2); printf("\nInverse of vec2: "); for(i = 0; i < sizeof(vec3)/sizeof(int); i++) { printf("%g ", vec2[i]); } Cross(vec1, vec2, vec3); printf("\nCross of vec1 and vec2: "); for(i = 0; i < sizeof(vec3)/sizeof(int); i++) { printf("%g ", vec3[i]); } Magnitude(vec2); printf("\nMagnitude of vec2: "); printf("%g ", Magnitude(vec2)); Normalize(vec2); printf("\nNormalize of vec2: "); for(i = 0; i < sizeof(vec3)/sizeof(int); i++) { printf("%g ", vec2[i]); } }
float Light::Phong_Model(Vector v, Vector l, Vector n, float f) { Vector r = (n * (2 * DotProduct(l, n))) - l; float vr = DotProduct(v, r.Normalize()); return pow(vr, f); }
void R_RecursiveWorldNode (mnode_t *node, int clipflags) { int i, c, side, *pindex; vec3_t acceptpt, rejectpt; mplane_t *plane; msurface_t *surf, **mark; mleaf_t *pleaf; double d, dot; if (node->contents == CONTENTS_SOLID) return; // solid if (node->visframe != r_visframecount) return; // cull the clipping planes if not trivial accept // FIXME: the compiler is doing a lousy job of optimizing here; it could be twice as fast in ASM if (clipflags) { for (i = 0; i < 4; i++) { if (!(clipflags & (1<<i)) ) continue; // don't need to clip against it // generate accept and reject points // FIXME: do with fast look-ups or integer tests based on the sign bit of the floating point values pindex = pfrustum_indexes[i]; rejectpt[0] = (float)node->minmaxs[pindex[0]]; rejectpt[1] = (float)node->minmaxs[pindex[1]]; rejectpt[2] = (float)node->minmaxs[pindex[2]]; d = DotProduct (rejectpt, view_clipplanes[i].normal); d -= view_clipplanes[i].dist; if (d <= 0) return; acceptpt[0] = (float)node->minmaxs[pindex[3+0]]; acceptpt[1] = (float)node->minmaxs[pindex[3+1]]; acceptpt[2] = (float)node->minmaxs[pindex[3+2]]; d = DotProduct (acceptpt, view_clipplanes[i].normal); d -= view_clipplanes[i].dist; if (d >= 0) clipflags &= ~(1<<i); // node is entirely on screen } } // if a leaf node, draw stuff if (node->contents < 0) { pleaf = (mleaf_t *)node; mark = pleaf->firstmarksurface; c = pleaf->nummarksurfaces; if (c) { do { (*mark)->visframe = r_framecount; mark++; } while (--c); } // deal with model fragments in this leaf if (pleaf->efrags) R_StoreEfrags (&pleaf->efrags); pleaf->key = r_currentkey; r_currentkey++; // all bmodels in a leaf share the same key } else { // node is just a decision point, so go down the apropriate sides // find which side of the node we are on plane = node->plane; dot = PlaneDiff (modelorg, plane); side = (dot < 0); // recurse down the children, front side first R_RecursiveWorldNode (node->children[side], clipflags); // draw stuff c = node->numsurfaces; if (c) { surf = cl.worldmodel->surfaces + node->firstsurface; if (dot < -BACKFACE_EPSILON) { do { if ((surf->flags & SURF_PLANEBACK) && surf->visframe == r_framecount) R_RenderFace (surf, clipflags); surf++; } while (--c); } else if (dot > BACKFACE_EPSILON) { do { if (!(surf->flags & SURF_PLANEBACK) && surf->visframe == r_framecount) R_RenderFace (surf, clipflags); surf++; } while (--c); } // all surfaces on the same node share the same sequence number r_currentkey++; } // recurse down the back side R_RecursiveWorldNode (node->children[!side], clipflags); } }
float Light::MicroFacet(Vector l, Vector v, Vector n, float m) { Vector h = (l + v) / Norm(l + v); float J = acos(DotProduct(h, n)); auto Beckmann = static_cast<float>((1 / (4.0f * (m * m) * pow((cos(J)), 4))) * exp((-1.0f * (tan(J) * tan(J))) / (m * m))); return Beckmann; }
void MakeScales(const int threadnum) { int i; unsigned j; vec3_t delta; vec_t dist; int count; float trans; patch_t* patch; patch_t* patch2; vec3_t origin; vec_t area; const vec_t* normal1; const vec_t* normal2; #ifdef HLRAD_HULLU #ifdef HLRAD_TRANSPARENCY_CPP unsigned int fastfind_index = 0; #endif #endif vec_t total; #ifdef HLRAD_TRANSFERDATA_COMPRESS transfer_raw_index_t* tIndex; float* tData; transfer_raw_index_t* tIndex_All = (transfer_raw_index_t*)AllocBlock(sizeof(transfer_index_t) * MAX_PATCHES); float* tData_All = (float*)AllocBlock(sizeof(float) * MAX_PATCHES); #else transfer_raw_index_t* tIndex; transfer_data_t* tData; transfer_raw_index_t* tIndex_All = (transfer_raw_index_t*)AllocBlock(sizeof(transfer_index_t) * MAX_PATCHES); transfer_data_t* tData_All = (transfer_data_t*)AllocBlock(sizeof(transfer_data_t) * MAX_PATCHES); #endif count = 0; while (1) { i = GetThreadWork(); if (i == -1) break; patch = g_patches + i; patch->iIndex = 0; patch->iData = 0; #ifndef HLRAD_TRANSNONORMALIZE total = 0.0; #endif tIndex = tIndex_All; tData = tData_All; VectorCopy(patch->origin, origin); normal1 = getPlaneFromFaceNumber(patch->faceNumber)->normal; area = patch->area; #ifdef HLRAD_TRANSLUCENT vec3_t backorigin; vec3_t backnormal; if (patch->translucent_b) { VectorMA (patch->origin, -(g_translucentdepth + 2*PATCH_HUNT_OFFSET), normal1, backorigin); VectorSubtract (vec3_origin, normal1, backnormal); } #endif #ifdef HLRAD_DIVERSE_LIGHTING bool lighting_diversify; vec_t lighting_power; vec_t lighting_scale; int miptex = g_texinfo[g_dfaces[patch->faceNumber].texinfo].miptex; lighting_power = g_lightingconeinfo[miptex][0]; lighting_scale = g_lightingconeinfo[miptex][1]; lighting_diversify = (lighting_power != 1.0 || lighting_scale != 1.0); #endif // find out which patch2's will collect light // from patch // HLRAD_NOSWAP: patch collect light from patch2 for (j = 0, patch2 = g_patches; j < g_num_patches; j++, patch2++) { vec_t dot1; vec_t dot2; #ifdef HLRAD_HULLU vec3_t transparency = {1.0,1.0,1.0}; #endif #ifdef HLRAD_TRANSLUCENT bool useback; useback = false; #endif if (!g_CheckVisBit(i, j #ifdef HLRAD_HULLU , transparency #ifdef HLRAD_TRANSPARENCY_CPP , fastfind_index #endif #endif ) || (i == j)) { #ifdef HLRAD_TRANSLUCENT if (patch->translucent_b) { if ((i == j) || !CheckVisBitBackwards(i, j, backorigin, backnormal #ifdef HLRAD_HULLU , transparency #endif )) { continue; } useback = true; } else { continue; } #else continue; #endif } normal2 = getPlaneFromFaceNumber(patch2->faceNumber)->normal; // calculate transferemnce VectorSubtract(patch2->origin, origin, delta); #ifdef HLRAD_TRANSLUCENT if (useback) { VectorSubtract (patch2->origin, backorigin, delta); } #endif #ifdef HLRAD_ACCURATEBOUNCE // move emitter back to its plane VectorMA (delta, -PATCH_HUNT_OFFSET, normal2, delta); #endif dist = VectorNormalize(delta); dot1 = DotProduct(delta, normal1); #ifdef HLRAD_TRANSLUCENT if (useback) { dot1 = DotProduct (delta, backnormal); } #endif dot2 = -DotProduct(delta, normal2); #ifdef HLRAD_ACCURATEBOUNCE #ifdef HLRAD_ACCURATEBOUNCE_ALTERNATEORIGIN bool light_behind_surface = false; if (dot1 <= NORMAL_EPSILON) { light_behind_surface = true; } #else if (dot1 <= NORMAL_EPSILON) { continue; } #endif if (dot2 * dist <= MINIMUM_PATCH_DISTANCE) { continue; } #endif #ifdef HLRAD_DIVERSE_LIGHTING if (lighting_diversify #ifdef HLRAD_ACCURATEBOUNCE_ALTERNATEORIGIN && !light_behind_surface #endif ) { dot1 = lighting_scale * pow (dot1, lighting_power); } #endif trans = (dot1 * dot2) / (dist * dist); // Inverse square falloff factoring angle between patch normals #ifdef HLRAD_TRANSWEIRDFIX #ifdef HLRAD_NOSWAP if (trans * patch2->area > 0.8f) trans = 0.8f / patch2->area; #else // HLRAD_TRANSWEIRDFIX: // we should limit "trans(patch2receive) * patch1area" // instead of "trans(patch2receive) * patch2area". // also raise "0.4f" to "0.8f" ( 0.8/Q_PI = 1/4). if (trans * area > 0.8f) trans = 0.8f / area; #endif #endif #ifdef HLRAD_ACCURATEBOUNCE if (dist < patch2->emitter_range - ON_EPSILON) { #ifdef HLRAD_ACCURATEBOUNCE_ALTERNATEORIGIN if (light_behind_surface) { trans = 0.0; } #endif vec_t sightarea; const vec_t *receiver_origin; const vec_t *receiver_normal; const Winding *emitter_winding; receiver_origin = origin; receiver_normal = normal1; #ifdef HLRAD_TRANSLUCENT if (useback) { receiver_origin = backorigin; receiver_normal = backnormal; } #endif emitter_winding = patch2->winding; sightarea = CalcSightArea (receiver_origin, receiver_normal, emitter_winding, patch2->emitter_skylevel #ifdef HLRAD_DIVERSE_LIGHTING , lighting_power, lighting_scale #endif ); vec_t frac; frac = dist / patch2->emitter_range; frac = (frac - 0.5f) * 2.0f; // make a smooth transition between the two methods frac = max (0, min (frac, 1)); trans = frac * trans + (1 - frac) * (sightarea / patch2->area); // because later we will multiply this back } #ifdef HLRAD_ACCURATEBOUNCE_ALTERNATEORIGIN else { if (light_behind_surface) { continue; } } #endif #endif #ifdef HLRAD_ACCURATEBOUNCE_REDUCEAREA trans *= patch2->exposure; #endif #ifdef HLRAD_HULLU trans = trans * VectorAvg(transparency); //hullu: add transparency effect #endif #ifdef HLRAD_TRANSLUCENT if (patch->translucent_b) { if (useback) { trans *= VectorAvg (patch->translucent_v); } else { trans *= 1 - VectorAvg (patch->translucent_v); } } #endif #ifndef HLRAD_ACCURATEBOUNCE if (trans >= 0) #endif { #ifndef HLRAD_TRANSWEIRDFIX #ifdef HLRAD_NOSWAP send = trans * area; #else send = trans * patch2->area; #endif // Caps light from getting weird if (send > 0.4f) { #ifdef HLRAD_NOSWAP trans = 0.4f / area; #else trans = 0.4f / patch2->area; #endif send = 0.4f; } #endif /*HLRAD_TRANSWEIRDFIX*/ #ifndef HLRAD_TRANSNONORMALIZE total += send; #endif #ifdef HLRAD_TRANSFERDATA_COMPRESS trans = trans * patch2->area; #else // scale to 16 bit (black magic) // BUG: (in MakeRGBScales) convert to integer will lose data. --vluzacn #ifdef HLRAD_NOSWAP trans = trans * patch2->area * INVERSE_TRANSFER_SCALE; #else trans = trans * area * INVERSE_TRANSFER_SCALE; #endif /*HLRAD_NOSWAP*/ if (trans >= TRANSFER_SCALE_MAX) { trans = TRANSFER_SCALE_MAX; } #endif } #ifndef HLRAD_ACCURATEBOUNCE else { #if 0 Warning("transfer < 0 (%f): dist=(%f)\n" " dot1=(%f) patch@(%4.3f %4.3f %4.3f) normal(%4.3f %4.3f %4.3f)\n" " dot2=(%f) patch@(%4.3f %4.3f %4.3f) normal(%4.3f %4.3f %4.3f)\n", trans, dist, dot1, patch->origin[0], patch->origin[1], patch->origin[2], patch->normal[0], patch->normal[1], patch->normal[2], dot2, patch2->origin[0], patch2->origin[1], patch2->origin[2], patch2->normal[0], patch2->normal[1], patch2->normal[2]); #endif trans = 0.0; } #endif #ifdef HLRAD_ACCURATEBOUNCE if (trans <= 0.0) { continue; } #endif *tData = trans; *tIndex = j; tData++; tIndex++; patch->iData++; count++; } // copy the transfers out if (patch->iData) { #ifdef HLRAD_TRANSFERDATA_COMPRESS unsigned data_size = patch->iData * float_size[g_transfer_compress_type] + unused_size; #else unsigned data_size = patch->iData * sizeof(transfer_data_t); #endif patch->tData = (transfer_data_t*)AllocBlock(data_size); patch->tIndex = CompressTransferIndicies(tIndex_All, patch->iData, &patch->iIndex); hlassume(patch->tData != NULL, assume_NoMemory); hlassume(patch->tIndex != NULL, assume_NoMemory); ThreadLock(); g_transfer_data_bytes += data_size; ThreadUnlock(); #ifdef HLRAD_REFLECTIVITY total = 1 / Q_PI; #else #ifdef HLRAD_TRANSNONORMALIZE #ifdef HLRAD_TRANSTOTAL_HACK total = g_transtotal_hack / Q_PI; #else total = 0.5 / Q_PI; #endif #else // BAD assumption when there is SKY. // // normalize all transfers so exactly 50% of the light // is transfered to the surroundings // total = 0.5 / total; #endif #endif { #ifdef HLRAD_TRANSFERDATA_COMPRESS unsigned x; transfer_data_t* t1 = patch->tData; float* t2 = tData_All; float f; for (x = 0; x < patch->iData; x++, t1+=float_size[g_transfer_compress_type], t2++) { f = (*t2) * total; float_compress (g_transfer_compress_type, t1, &f); } #else unsigned x; transfer_data_t* t1 = patch->tData; transfer_data_t* t2 = tData_All; for (x = 0; x < patch->iData; x++, t1++, t2++) { (*t1) = (*t2) * total; } #endif } } } FreeBlock(tIndex_All); FreeBlock(tData_All); ThreadLock(); g_total_transfer += count; ThreadUnlock(); }
/* =============== CG_OffsetFirstPersonView =============== */ static void CG_OffsetFirstPersonView( void ) { float *origin; float *angles; float bob; float ratio; float delta; float speed; float f; vec3_t predictedVelocity; int timeDelta; float bob2; vec3_t normal, baseOrigin; playerState_t *ps = &cg.predictedPlayerState; if( ps->stats[ STAT_STATE ] & SS_WALLCLIMBING ) { if( ps->stats[ STAT_STATE ] & SS_WALLCLIMBINGCEILING ) VectorSet( normal, 0.0f, 0.0f, -1.0f ); else VectorCopy( ps->grapplePoint, normal ); } else VectorSet( normal, 0.0f, 0.0f, 1.0f ); if( cg.snap->ps.pm_type == PM_INTERMISSION ) return; origin = cg.refdef.vieworg; angles = cg.refdefViewAngles; VectorCopy( origin, baseOrigin ); // if dead, fix the angle and don't add any kick if( cg.snap->ps.stats[ STAT_HEALTH ] <= 0 ) { angles[ ROLL ] = 40; angles[ PITCH ] = -15; angles[ YAW ] = cg.snap->ps.stats[ STAT_VIEWLOCK ]; origin[ 2 ] += cg.predictedPlayerState.viewheight; return; } // add angles based on weapon kick VectorAdd( angles, cg.kick_angles, angles ); // add angles based on damage kick if( cg.damageTime ) { ratio = cg.time - cg.damageTime; if( ratio < DAMAGE_DEFLECT_TIME ) { ratio /= DAMAGE_DEFLECT_TIME; angles[ PITCH ] += ratio * cg.v_dmg_pitch; angles[ ROLL ] += ratio * cg.v_dmg_roll; } else { ratio = 1.0 - ( ratio - DAMAGE_DEFLECT_TIME ) / DAMAGE_RETURN_TIME; if( ratio > 0 ) { angles[ PITCH ] += ratio * cg.v_dmg_pitch; angles[ ROLL ] += ratio * cg.v_dmg_roll; } } } // add pitch based on fall kick #if 0 ratio = ( cg.time - cg.landTime) / FALL_TIME; if (ratio < 0) ratio = 0; angles[PITCH] += ratio * cg.fall_value; #endif // add angles based on velocity VectorCopy( cg.predictedPlayerState.velocity, predictedVelocity ); delta = DotProduct( predictedVelocity, cg.refdef.viewaxis[ 0 ] ); angles[ PITCH ] += delta * cg_runpitch.value; delta = DotProduct( predictedVelocity, cg.refdef.viewaxis[ 1 ] ); angles[ ROLL ] -= delta * cg_runroll.value; // add angles based on bob // bob amount is class dependant if( cg.snap->ps.persistant[ PERS_TEAM ] == TEAM_SPECTATOR ) bob2 = 0.0f; else bob2 = BG_FindBobForClass( cg.predictedPlayerState.stats[ STAT_PCLASS ] ); #define LEVEL4_FEEDBACK 10.0f //give a charging player some feedback if( ps->weapon == WP_ALEVEL4 ) { if( ps->stats[ STAT_MISC ] > 0 ) { float fraction = (float)ps->stats[ STAT_MISC ] / (float)LEVEL4_CHARGE_TIME; if( fraction > 1.0f ) fraction = 1.0f; bob2 *= ( 1.0f + fraction * LEVEL4_FEEDBACK ); } } if( bob2 != 0.0f ) { // make sure the bob is visible even at low speeds speed = cg.xyspeed > 200 ? cg.xyspeed : 200; delta = cg.bobfracsin * ( bob2 ) * speed; if( cg.predictedPlayerState.pm_flags & PMF_DUCKED ) delta *= 3; // crouching angles[ PITCH ] += delta; delta = cg.bobfracsin * ( bob2 ) * speed; if( cg.predictedPlayerState.pm_flags & PMF_DUCKED ) delta *= 3; // crouching accentuates roll if( cg.bobcycle & 1 ) delta = -delta; angles[ ROLL ] += delta; } #define LEVEL3_FEEDBACK 20.0f //provide some feedback for pouncing if( cg.predictedPlayerState.weapon == WP_ALEVEL3 || cg.predictedPlayerState.weapon == WP_ALEVEL3_UPG ) { if( cg.predictedPlayerState.stats[ STAT_MISC ] > 0 ) { float fraction1, fraction2; vec3_t forward; AngleVectors( angles, forward, NULL, NULL ); VectorNormalize( forward ); fraction1 = (float)( cg.time - cg.weapon2Time ) / (float)LEVEL3_POUNCE_CHARGE_TIME; if( fraction1 > 1.0f ) fraction1 = 1.0f; fraction2 = -sin( fraction1 * M_PI / 2 ); VectorMA( origin, LEVEL3_FEEDBACK * fraction2, forward, origin ); } } #define STRUGGLE_DIST 5.0f #define STRUGGLE_TIME 250 //allow the player to struggle a little whilst grabbed if( cg.predictedPlayerState.pm_type == PM_GRABBED ) { vec3_t forward, right, up; usercmd_t cmd; int cmdNum; float fFraction, rFraction, uFraction; float fFraction2, rFraction2, uFraction2; cmdNum = trap_GetCurrentCmdNumber(); trap_GetUserCmd( cmdNum, &cmd ); AngleVectors( angles, forward, right, up ); fFraction = (float)( cg.time - cg.forwardMoveTime ) / STRUGGLE_TIME; rFraction = (float)( cg.time - cg.rightMoveTime ) / STRUGGLE_TIME; uFraction = (float)( cg.time - cg.upMoveTime ) / STRUGGLE_TIME; if( fFraction > 1.0f ) fFraction = 1.0f; if( rFraction > 1.0f ) rFraction = 1.0f; if( uFraction > 1.0f ) uFraction = 1.0f; fFraction2 = -sin( fFraction * M_PI / 2 ); rFraction2 = -sin( rFraction * M_PI / 2 ); uFraction2 = -sin( uFraction * M_PI / 2 ); if( cmd.forwardmove > 0 ) VectorMA( origin, STRUGGLE_DIST * fFraction, forward, origin ); else if( cmd.forwardmove < 0 ) VectorMA( origin, -STRUGGLE_DIST * fFraction, forward, origin ); else cg.forwardMoveTime = cg.time; if( cmd.rightmove > 0 ) VectorMA( origin, STRUGGLE_DIST * rFraction, right, origin ); else if( cmd.rightmove < 0 ) VectorMA( origin, -STRUGGLE_DIST * rFraction, right, origin ); else cg.rightMoveTime = cg.time; if( cmd.upmove > 0 ) VectorMA( origin, STRUGGLE_DIST * uFraction, up, origin ); else if( cmd.upmove < 0 ) VectorMA( origin, -STRUGGLE_DIST * uFraction, up, origin ); else cg.upMoveTime = cg.time; } if( cg.predictedPlayerState.stats[ STAT_STATE ] & SS_POISONCLOUDED && !( cg.snap->ps.pm_flags & PMF_FOLLOW ) ) { float fraction = sin( ( (float)cg.time / 1000.0f ) * M_PI * 2 * PCLOUD_ROLL_FREQUENCY ); float pitchFraction = sin( ( (float)cg.time / 1000.0f ) * M_PI * 5 * PCLOUD_ROLL_FREQUENCY ); fraction *= 1.0f - ( ( cg.time - cg.poisonedTime ) / (float)LEVEL1_PCLOUD_TIME ); pitchFraction *= 1.0f - ( ( cg.time - cg.poisonedTime ) / (float)LEVEL1_PCLOUD_TIME ); angles[ ROLL ] += fraction * PCLOUD_ROLL_AMPLITUDE; angles[ YAW ] += fraction * PCLOUD_ROLL_AMPLITUDE; angles[ PITCH ] += pitchFraction * PCLOUD_ROLL_AMPLITUDE / 2.0f; } // this *feels* more realisitic for humans if( cg.predictedPlayerState.stats[ STAT_PTEAM ] == PTE_HUMANS ) { angles[PITCH] += cg.bobfracsin * bob2 * 0.5; // heavy breathing effects //FIXME: sound if( cg.predictedPlayerState.stats[ STAT_STAMINA ] < 0 ) { float deltaBreath = (float)( cg.predictedPlayerState.stats[ STAT_STAMINA ] < 0 ? -cg.predictedPlayerState.stats[ STAT_STAMINA ] : cg.predictedPlayerState.stats[ STAT_STAMINA ] ) / 200.0; float deltaAngle = cos( (float)cg.time/150.0 ) * deltaBreath; deltaAngle += ( deltaAngle < 0 ? -deltaAngle : deltaAngle ) * 0.5; angles[ PITCH ] -= deltaAngle; } //ZdrytchX: Personal view bug fix hack [see youtube.com/zdrytchx: mdriver false bullet physics test, //you'll see how annoying it is in sniping for me, turns out the correction value for myself is approx //-1.19 degrees that actualy changes with pitch... I need to find a way to fix this.] //@jkent: Thinking of which, I have an idea: facetracker compatability, haha... if( cg_firstpersonanglefix_yaw.value != 0) { if( cg_firstpersonanglefix_yaw.value > 20) //TODO: make sure we don't cheat here! (doesn't work) trap_Cvar_Set( "cg_firstpersonanglefix_yaw.value", "20" ); else if( cg_firstpersonanglefix_yaw.value < -20) trap_Cvar_Set( "cg_firstpersonanglefix_yaw.value", "-20" ); //Set angle fix! angles[ YAW ] += cg_firstpersonanglefix_yaw.value; //left is positive (backward people's tradition) } if( cg_firstpersonanglefix_pitch.value != 0) { if( cg_firstpersonanglefix_pitch.value > 20) //TODO: make sure we don't cheat here! (doesn't work) trap_Cvar_Set( "cg_firstpersonanglefix_pitch.value", "20" ); else if( cg_firstpersonanglefix_pitch.value < -20) trap_Cvar_Set( "cg_firstpersonanglefix_pitch.value", "-20" ); //Set angle fix! angles[ PITCH ] -= cg_firstpersonanglefix_pitch.value; //up is positive } } //=================================== // add view height // when wall climbing the viewheight is not straight up if( cg.predictedPlayerState.stats[ STAT_STATE ] & SS_WALLCLIMBING ) VectorMA( origin, ps->viewheight, normal, origin ); else origin[ 2 ] += cg.predictedPlayerState.viewheight; // smooth out duck height changes timeDelta = cg.time - cg.duckTime; if( timeDelta < DUCK_TIME) { cg.refdef.vieworg[ 2 ] -= cg.duckChange * ( DUCK_TIME - timeDelta ) / DUCK_TIME; } // add bob height bob = cg.bobfracsin * cg.xyspeed * bob2; if( bob > 6 ) bob = 6; // likewise for bob if( cg.predictedPlayerState.stats[ STAT_STATE ] & SS_WALLCLIMBING ) VectorMA( origin, bob, normal, origin ); else origin[ 2 ] += bob; // add fall height delta = cg.time - cg.landTime; if( delta < LAND_DEFLECT_TIME ) { f = delta / LAND_DEFLECT_TIME; cg.refdef.vieworg[ 2 ] += cg.landChange * f; } else if( delta < LAND_DEFLECT_TIME + LAND_RETURN_TIME ) { delta -= LAND_DEFLECT_TIME; f = 1.0 - ( delta / LAND_RETURN_TIME ); cg.refdef.vieworg[ 2 ] += cg.landChange * f; } // add step offset CG_StepOffset( ); // add kick offset VectorAdd (origin, cg.kick_origin, origin); }
/* =============== CG_OffsetFirstPersonView =============== */ static void CG_OffsetFirstPersonView( void ) { float *origin; float *angles; float bob; float ratio; float delta; float speed; float f; vec3_t predictedVelocity; int timeDelta; if ( cg.snap->ps.pm_type == PM_INTERMISSION ) { return; } origin = cg.refdef.vieworg; angles = cg.refdefViewAngles; // if dead, fix the angle and don't add any kick if ( cg.snap->ps.stats[STAT_HEALTH] <= 0 ) { angles[ROLL] = 40; angles[PITCH] = -15; angles[YAW] = cg.snap->ps.stats[STAT_DEAD_YAW]; origin[2] += cg.predictedPlayerState.viewheight; return; } // add angles based on weapon kick VectorAdd( angles, cg.kick_angles, angles ); // RF, add new weapon kick angles CG_KickAngles(); VectorAdd( angles, cg.kickAngles, angles ); // RF, pitch is already added //angles[0] -= cg.kickAngles[PITCH]; // add angles based on damage kick if ( cg.damageTime ) { ratio = cg.time - cg.damageTime; if ( ratio < DAMAGE_DEFLECT_TIME ) { ratio /= DAMAGE_DEFLECT_TIME; angles[PITCH] += ratio * cg.v_dmg_pitch; angles[ROLL] += ratio * cg.v_dmg_roll; } else { ratio = 1.0 - ( ratio - DAMAGE_DEFLECT_TIME ) / DAMAGE_RETURN_TIME; if ( ratio > 0 ) { angles[PITCH] += ratio * cg.v_dmg_pitch; angles[ROLL] += ratio * cg.v_dmg_roll; } } } // add pitch based on fall kick #if 0 ratio = ( cg.time - cg.landTime ) / FALL_TIME; if ( ratio < 0 ) { ratio = 0; } angles[PITCH] += ratio * cg.fall_value; #endif // add angles based on velocity VectorCopy( cg.predictedPlayerState.velocity, predictedVelocity ); delta = DotProduct( predictedVelocity, cg.refdef.viewaxis[0] ); angles[PITCH] += delta * cg_runpitch.value; delta = DotProduct( predictedVelocity, cg.refdef.viewaxis[1] ); angles[ROLL] -= delta * cg_runroll.value; // add angles based on bob // make sure the bob is visible even at low speeds speed = cg.xyspeed > 200 ? cg.xyspeed : 200; delta = cg.bobfracsin * cg_bobpitch.value * speed; if ( cg.predictedPlayerState.pm_flags & PMF_DUCKED ) { delta *= 3; // crouching } angles[PITCH] += delta; delta = cg.bobfracsin * cg_bobroll.value * speed; if ( cg.predictedPlayerState.pm_flags & PMF_DUCKED ) { delta *= 3; // crouching accentuates roll } if ( cg.bobcycle & 1 ) { delta = -delta; } angles[ROLL] += delta; //=================================== // add view height origin[2] += cg.predictedPlayerState.viewheight; // smooth out duck height changes timeDelta = cg.time - cg.duckTime; if ( timeDelta < 0 ) { // Ridah cg.duckTime = cg.time - DUCK_TIME; } if ( timeDelta < DUCK_TIME ) { cg.refdef.vieworg[2] -= cg.duckChange * ( DUCK_TIME - timeDelta ) / DUCK_TIME; } // add bob height bob = cg.bobfracsin * cg.xyspeed * cg_bobup.value; if ( bob > 6 ) { bob = 6; } origin[2] += bob; // add fall height delta = cg.time - cg.landTime; if ( delta < 0 ) { // Ridah cg.landTime = cg.time - ( LAND_DEFLECT_TIME + LAND_RETURN_TIME ); } if ( delta < LAND_DEFLECT_TIME ) { f = delta / LAND_DEFLECT_TIME; cg.refdef.vieworg[2] += cg.landChange * f; } else if ( delta < LAND_DEFLECT_TIME + LAND_RETURN_TIME ) { delta -= LAND_DEFLECT_TIME; f = 1.0 - ( delta / LAND_RETURN_TIME ); cg.refdef.vieworg[2] += cg.landChange * f; } // add step offset CG_StepOffset(); CG_ZoomSway(); // adjust for 'lean' if ( cg.predictedPlayerState.leanf != 0 ) { //add leaning offset vec3_t right; cg.refdefViewAngles[2] += cg.predictedPlayerState.leanf / 2.0f; AngleVectors( cg.refdefViewAngles, NULL, right, NULL ); VectorMA( cg.refdef.vieworg, cg.predictedPlayerState.leanf, right, cg.refdef.vieworg ); } // add kick offset VectorAdd( origin, cg.kick_origin, origin ); // pivot the eye based on a neck length #if 0 { #define NECK_LENGTH 8 vec3_t forward, up; cg.refdef.vieworg[2] -= NECK_LENGTH; AngleVectors( cg.refdefViewAngles, forward, NULL, up ); VectorMA( cg.refdef.vieworg, 3, forward, cg.refdef.vieworg ); VectorMA( cg.refdef.vieworg, NECK_LENGTH, up, cg.refdef.vieworg ); } #endif }
/* =============== CG_smoothWWTransitions =============== */ static void CG_smoothWWTransitions( playerState_t *ps, const vec3_t in, vec3_t out ) { vec3_t surfNormal, rotAxis, temp; vec3_t refNormal = { 0.0f, 0.0f, 1.0f }; vec3_t ceilingNormal = { 0.0f, 0.0f, -1.0f }; int i; float stLocal, sFraction, rotAngle; float smoothTime, timeMod; qboolean performed = qfalse; vec3_t inAxis[ 3 ], lastAxis[ 3 ], outAxis[ 3 ]; if( cg.snap->ps.pm_flags & PMF_FOLLOW ) { VectorCopy( in, out ); return; } //set surfNormal if( !( ps->stats[ STAT_STATE ] & SS_WALLCLIMBINGCEILING ) ) VectorCopy( ps->grapplePoint, surfNormal ); else VectorCopy( ceilingNormal, surfNormal ); AnglesToAxis( in, inAxis ); //if we are moving from one surface to another smooth the transition if( !VectorCompare( surfNormal, cg.lastNormal ) ) { //if we moving from the ceiling to the floor special case //( x product of colinear vectors is undefined) if( VectorCompare( ceilingNormal, cg.lastNormal ) && VectorCompare( refNormal, surfNormal ) ) { AngleVectors( in, temp, NULL, NULL ); ProjectPointOnPlane( rotAxis, temp, refNormal ); VectorNormalize( rotAxis ); rotAngle = 180.0f; timeMod = 1.5f; } else { AnglesToAxis( cg.lastVangles, lastAxis ); rotAngle = DotProduct( inAxis[ 0 ], lastAxis[ 0 ] ) + DotProduct( inAxis[ 1 ], lastAxis[ 1 ] ) + DotProduct( inAxis[ 2 ], lastAxis[ 2 ] ); rotAngle = RAD2DEG( acos( ( rotAngle - 1.0f ) / 2.0f ) ); CrossProduct( lastAxis[ 0 ], inAxis[ 0 ], temp ); VectorCopy( temp, rotAxis ); CrossProduct( lastAxis[ 1 ], inAxis[ 1 ], temp ); VectorAdd( rotAxis, temp, rotAxis ); CrossProduct( lastAxis[ 2 ], inAxis[ 2 ], temp ); VectorAdd( rotAxis, temp, rotAxis ); VectorNormalize( rotAxis ); timeMod = 1.0f; } //add the op CG_addSmoothOp( rotAxis, rotAngle, timeMod ); } //iterate through ops for( i = MAXSMOOTHS - 1; i >= 0; i-- ) { smoothTime = (int)( cg_wwSmoothTime.integer * cg.sList[ i ].timeMod ); //if this op has time remaining, perform it if( cg.time < cg.sList[ i ].time + smoothTime ) { stLocal = 1.0f - ( ( ( cg.sList[ i ].time + smoothTime ) - cg.time ) / smoothTime ); sFraction = -( cos( stLocal * M_PI ) + 1.0f ) / 2.0f; RotatePointAroundVector( outAxis[ 0 ], cg.sList[ i ].rotAxis, inAxis[ 0 ], sFraction * cg.sList[ i ].rotAngle ); RotatePointAroundVector( outAxis[ 1 ], cg.sList[ i ].rotAxis, inAxis[ 1 ], sFraction * cg.sList[ i ].rotAngle ); RotatePointAroundVector( outAxis[ 2 ], cg.sList[ i ].rotAxis, inAxis[ 2 ], sFraction * cg.sList[ i ].rotAngle ); AxisCopy( outAxis, inAxis ); performed = qtrue; } } //if we performed any ops then return the smoothed angles //otherwise simply return the in angles if( performed ) AxisToAngles( outAxis, out ); else VectorCopy( in, out ); //copy the current normal to the lastNormal VectorCopy( in, cg.lastVangles ); VectorCopy( surfNormal, cg.lastNormal ); }
/*static*/ float CVector3f::DotProduct( const CVector3f &v1, const CVector3f &v2 ) { return DotProduct( v1.x, v1.y, v1.z, v2.x, v2.y, v2.z ); }
//rwwFIXMEFIXME: This is all going to have to be predicted I think, or it will feel awful //and lagged // This function makes sure that the rider's in this vehicle are properly animated. static void AnimateRiders( Vehicle_t *pVeh ) { animNumber_t Anim = BOTH_VT_IDLE; int iFlags = SETANIM_FLAG_NORMAL, iBlend = 500; gentity_t *pilot = (gentity_t *)pVeh->m_pPilot; gentity_t *parent = (gentity_t *)pVeh->m_pParentEntity; playerState_t *pilotPS; playerState_t *parentPS; float fSpeedPercToMax; #ifdef _JK2MP pilotPS = pVeh->m_pPilot->playerState; parentPS = pVeh->m_pPilot->playerState; #else pilotPS = &pVeh->m_pPilot->client->ps; parentPS = &pVeh->m_pParentEntity->client->ps; #endif // Boarding animation. if ( pVeh->m_iBoarding != 0 ) { return; } // Percentage of maximum speed relative to current speed. fSpeedPercToMax = parent->client->ps.speed / pVeh->m_pVehicleInfo->speedMax; // Going in reverse... #ifdef _JK2MP //handled in pmove in mp if (0) #else if ( fSpeedPercToMax < -0.01f ) #endif { Anim = BOTH_VT_WALK_REV; iBlend = 600; } else { bool HasWeapon = ((pilotPS->weapon != WP_NONE) && (pilotPS->weapon != WP_MELEE)); bool Attacking = (HasWeapon && !!(pVeh->m_ucmd.buttons&BUTTON_ATTACK)); bool Right = (pVeh->m_ucmd.rightmove>0); bool Left = (pVeh->m_ucmd.rightmove<0); bool Turbo = (fSpeedPercToMax>0.0f && level.time<pVeh->m_iTurboTime); bool Walking = (fSpeedPercToMax>0.0f && ((pVeh->m_ucmd.buttons&BUTTON_WALKING) || fSpeedPercToMax<=0.275f)); bool Running = (fSpeedPercToMax>0.275f); EWeaponPose WeaponPose = WPOSE_NONE; // Remove Crashing Flag //---------------------- pVeh->m_ulFlags &= ~VEH_CRASHING; // Put Away Saber When It Is Not Active //-------------------------------------- #ifndef _JK2MP if (HasWeapon && (Turbo || (pilotPS->weapon==WP_SABER && !pilotPS->SaberActive()))) { if (pVeh->m_pPilot->s.number<MAX_CLIENTS) { CG_ChangeWeapon(WP_NONE); } pVeh->m_pPilot->client->ps.weapon = WP_NONE; G_RemoveWeaponModels(pVeh->m_pPilot); } #endif // Don't Interrupt Attack Anims //------------------------------ #ifdef _JK2MP if (pilotPS->weaponTime>0) { return; } #else if (pilotPS->torsoAnim>=BOTH_VT_ATL_S && pilotPS->torsoAnim<=BOTH_VT_ATF_G) { float bodyCurrent = 0.0f; int bodyEnd = 0; if (!!gi.G2API_GetBoneAnimIndex(&pVeh->m_pPilot->ghoul2[pVeh->m_pPilot->playerModel], pVeh->m_pPilot->rootBone, level.time, &bodyCurrent, NULL, &bodyEnd, NULL, NULL, NULL)) { if (bodyCurrent<=((float)(bodyEnd)-1.5f)) { return; } } } #endif // Compute The Weapon Pose //-------------------------- if (pilotPS->weapon==WP_BLASTER) { WeaponPose = WPOSE_BLASTER; } else if (pilotPS->weapon==WP_SABER) { if ( (pVeh->m_ulFlags&VEH_SABERINLEFTHAND) && pilotPS->torsoAnim==BOTH_VT_ATL_TO_R_S) { pVeh->m_ulFlags &= ~VEH_SABERINLEFTHAND; } if (!(pVeh->m_ulFlags&VEH_SABERINLEFTHAND) && pilotPS->torsoAnim==BOTH_VT_ATR_TO_L_S) { pVeh->m_ulFlags |= VEH_SABERINLEFTHAND; } WeaponPose = (pVeh->m_ulFlags&VEH_SABERINLEFTHAND)?(WPOSE_SABERLEFT):(WPOSE_SABERRIGHT); } if (Attacking && WeaponPose) {// Attack! iBlend = 100; iFlags = SETANIM_FLAG_OVERRIDE|SETANIM_FLAG_HOLD|SETANIM_FLAG_RESTART; if (Turbo) { Right = true; Left = false; } // Auto Aiming //=============================================== if (!Left && !Right) // Allow player strafe keys to override { #ifndef _JK2MP if (pVeh->m_pPilot->enemy) { vec3_t toEnemy; float toEnemyDistance; vec3_t actorRight; float actorRightDot; VectorSubtract(pVeh->m_pPilot->currentOrigin, pVeh->m_pPilot->enemy->currentOrigin, toEnemy); toEnemyDistance = VectorNormalize(toEnemy); AngleVectors(pVeh->m_pParentEntity->currentAngles, 0, actorRight, 0); actorRightDot = DotProduct(toEnemy, actorRight); if (fabsf(actorRightDot)>0.5f || pilotPS->weapon==WP_SABER) { Left = (actorRightDot>0.0f); Right = !Left; } else { Right = Left = false; } } else #endif if (pilotPS->weapon==WP_SABER && !Left && !Right) { Left = (WeaponPose==WPOSE_SABERLEFT); Right = !Left; } } if (Left) {// Attack Left switch(WeaponPose) { case WPOSE_BLASTER: Anim = BOTH_VT_ATL_G; break; case WPOSE_SABERLEFT: Anim = BOTH_VT_ATL_S; break; case WPOSE_SABERRIGHT: Anim = BOTH_VT_ATR_TO_L_S; break; default: assert(0); } } else if (Right) {// Attack Right switch(WeaponPose) { case WPOSE_BLASTER: Anim = BOTH_VT_ATR_G; break; case WPOSE_SABERLEFT: Anim = BOTH_VT_ATL_TO_R_S; break; case WPOSE_SABERRIGHT: Anim = BOTH_VT_ATR_S; break; default: assert(0); } } else {// Attack Ahead switch(WeaponPose) { case WPOSE_BLASTER: Anim = BOTH_VT_ATF_G; break; default: assert(0); } } } else if (Turbo) {// Kicked In Turbo iBlend = 50; iFlags = SETANIM_FLAG_OVERRIDE; Anim = BOTH_VT_TURBO; } else {// No Special Moves iBlend = 300; iFlags = SETANIM_FLAG_OVERRIDE | SETANIM_FLAG_HOLDLESS; if (WeaponPose==WPOSE_NONE) { if (Walking) { Anim = BOTH_VT_WALK_FWD; } else if (Running) { Anim = BOTH_VT_RUN_FWD; } else { Anim = BOTH_VT_IDLE1;//(Q_irand(0,1)==0)?(BOTH_VT_IDLE):(BOTH_VT_IDLE1); } } else { switch(WeaponPose) { case WPOSE_BLASTER: Anim = BOTH_VT_IDLE_G; break; case WPOSE_SABERLEFT: Anim = BOTH_VT_IDLE_SL; break; case WPOSE_SABERRIGHT: Anim = BOTH_VT_IDLE_SR; break; default: assert(0); } } }// No Special Moves } Vehicle_SetAnim( pilot, SETANIM_BOTH, Anim, iFlags, iBlend ); }
/* ============ SV_FlyMove The basic solid body movement clip that slides along multiple planes *steptrace - if not NULL, the trace results of any vertical wall hit will be stored Returns the clipflags if the velocity was modified (hit something solid) 1 = floor 2 = wall / step 4 = dead stop ============ */ int SV_FlyMove( edict_t *ent, float time, trace_t *steptrace ) { int i, j, numplanes, bumpcount, blocked; vec3_t dir, end, planes[MAX_CLIP_PLANES]; vec3_t primal_velocity, original_velocity, new_velocity; float d, time_left, allFraction; trace_t trace; blocked = 0; VectorCopy( ent->v.velocity, original_velocity ); VectorCopy( ent->v.velocity, primal_velocity ); numplanes = 0; allFraction = 0.0f; time_left = time; for( bumpcount = 0; bumpcount < MAX_CLIP_PLANES - 1; bumpcount++ ) { if( VectorIsNull( ent->v.velocity )) break; VectorMA( ent->v.origin, time_left, ent->v.velocity, end ); trace = SV_Move( ent->v.origin, ent->v.mins, ent->v.maxs, end, MOVE_NORMAL, ent ); allFraction += trace.fraction; if( trace.allsolid ) { // entity is trapped in another solid VectorClear( ent->v.velocity ); return 4; } if( trace.fraction > 0.0f ) { // actually covered some distance VectorCopy( trace.endpos, ent->v.origin ); VectorCopy( ent->v.velocity, original_velocity ); numplanes = 0; } if( trace.fraction == 1.0f ) break; // moved the entire distance if( !trace.ent ) MsgDev( D_ERROR, "SV_FlyMove: trace.ent == NULL\n" ); if( trace.plane.normal[2] > 0.7f ) { blocked |= 1; // floor if( trace.ent->v.solid == SOLID_BSP || trace.ent->v.solid == SOLID_SLIDEBOX || trace.ent->v.movetype == MOVETYPE_PUSHSTEP || (trace.ent->v.flags & FL_CLIENT)) { ent->v.flags |= FL_ONGROUND; ent->v.groundentity = trace.ent; } } if( trace.plane.normal[2] == 0.0f ) { blocked |= 2; // step if( steptrace ) *steptrace = trace; // save for player extrafriction } // run the impact function SV_Impact( ent, trace.ent, &trace ); // break if removed by the impact function if( ent->free ) break; time_left -= time_left * trace.fraction; // clipped to another plane if( numplanes >= MAX_CLIP_PLANES ) { // this shouldn't really happen VectorClear( ent->v.velocity ); break; } VectorCopy( trace.plane.normal, planes[numplanes] ); numplanes++; // modify original_velocity so it parallels all of the clip planes for( i = 0; i < numplanes; i++ ) { SV_ClipVelocity( original_velocity, planes[i], new_velocity, 1.0f ); for( j = 0; j < numplanes; j++ ) { if( j != i ) { if( DotProduct( new_velocity, planes[j] ) < 0.0f ) break; // not ok } } if( j == numplanes ) break; } if( i != numplanes ) { // go along this plane VectorCopy( new_velocity, ent->v.velocity ); } else { // go along the crease if( numplanes != 2 ) { VectorClear( ent->v.velocity ); break; } CrossProduct( planes[0], planes[1], dir ); d = DotProduct( dir, ent->v.velocity ); VectorScale( dir, d, ent->v.velocity ); } // if current velocity is against the original velocity, // stop dead to avoid tiny occilations in sloping corners if( DotProduct( ent->v.velocity, primal_velocity ) <= 0.0f ) { VectorClear( ent->v.velocity ); break; } } if( allFraction == 0.0f ) VectorClear( ent->v.velocity ); return blocked; }
/* ================ AIFunc_WarriorZombieDefense ================ */ char *AIFunc_WarriorZombieDefense( cast_state_t *cs ) { gentity_t *ent, *enemy; vec3_t enemyDir, vec; float dist; ent = &g_entities[cs->entityNum]; if ( !( ent->flags & FL_DEFENSE_GUARD ) ) { if ( cs->weaponFireTimes[cs->weaponNum] < level.time - 100 ) { return AIFunc_DefaultStart( cs ); } return NULL; } if ( ( cs->enemyNum < 0 ) || ( cs->dangerEntityValidTime >= level.time ) ) { ent->flags &= ~FL_DEFENSE_GUARD; ent->client->ps.torsoTimer = 0; ent->client->ps.legsTimer = 0; return NULL; } enemy = &g_entities[cs->enemyNum]; if ( cs->thinkFuncChangeTime < level.time - 1500 ) { // if we cant see them if ( !AICast_EntityVisible( cs, cs->enemyNum, qtrue ) ) { ent->flags &= ~FL_DEFENSE_GUARD; ent->client->ps.torsoTimer = 0; ent->client->ps.legsTimer = 0; return NULL; } // if our enemy isn't using a dangerous weapon if ( enemy->client->ps.weapon < WP_LUGER || enemy->client->ps.weapon > WP_CLASS_SPECIAL ) { ent->flags &= ~FL_DEFENSE_GUARD; ent->client->ps.torsoTimer = 0; ent->client->ps.legsTimer = 0; return NULL; } // if our enemy isn't looking right at us, abort VectorSubtract( ent->client->ps.origin, enemy->client->ps.origin, vec ); dist = VectorNormalize( vec ); if ( dist > 512 ) { dist = 512; } AngleVectors( enemy->client->ps.viewangles, enemyDir, NULL, NULL ); if ( DotProduct( vec, enemyDir ) < ( 0.98 - 0.2 * ( dist / 512 ) ) ) { ent->flags &= ~FL_DEFENSE_GUARD; ent->client->ps.torsoTimer = 0; ent->client->ps.legsTimer = 0; return NULL; } } cs->weaponFireTimes[cs->weaponNum] = level.time; if ( !ent->client->ps.torsoTimer ) { ent->flags &= ~FL_DEFENSE_GUARD; ent->client->ps.torsoTimer = 0; ent->client->ps.legsTimer = 0; return NULL; } // face them AICast_AimAtEnemy( cs ); // crouching position, use smaller bounding box trap_EA_Crouch( cs->bs->client ); return NULL; }