CSmokeTrailProjectile::CSmokeTrailProjectile( const float3& pos1, const float3& pos2, const float3& dir1, const float3& dir2, CUnit* owner, bool firstSegment, bool lastSegment, float size, int time, float color, bool drawTrail, CProjectile* drawCallback, AtlasedTexture* texture): CProjectile((pos1 + pos2) * 0.5f, ZeroVector, owner, false, false, false), pos1(pos1), pos2(pos2), orgSize(size), creationTime(gs->frameNum), lifeTime(time), color(color), dir1(dir1), dir2(dir2), drawTrail(drawTrail), drawSegmented(false), firstSegment(firstSegment), lastSegment(lastSegment), drawCallbacker(drawCallback), texture(texture) { checkCol = false; castShadow = true; // if no custom texture is defined, use the default texture // Note that this will crash anyway (no idea why) so never have a null texture! if (texture == NULL) { texture = projectileDrawer->smoketrailtex; } if (!drawTrail) { const float dist = pos1.distance(pos2); dirpos1 = pos1 - dir1 * dist * 0.33f; dirpos2 = pos2 + dir2 * dist * 0.33f; } else if (dir1.dot(dir2) < 0.98f) { const float dist = pos1.distance(pos2); dirpos1 = pos1 - dir1 * dist * 0.33f; dirpos2 = pos2 + dir2 * dist * 0.33f; // float3 mp = (pos1 + pos2) / 2; midpos = CalcBeizer(0.5f, pos1, dirpos1, dirpos2, pos2); middir = (dir1 + dir2).ANormalize(); drawSegmented = true; } SetRadiusAndHeight(pos1.distance(pos2), 0.0f); if ((pos.y - ground->GetApproximateHeight(pos.x, pos.z)) > 10) { useAirLos = true; } }
CSmokeTrailProjectile::CSmokeTrailProjectile( CUnit* owner, const float3& pos1, const float3& pos2, const float3& dir1, const float3& dir2, bool firstSegment, bool lastSegment, float size, int time, float color, bool drawTrail, CProjectile* drawCallback, AtlasedTexture* texture ): CProjectile((pos1 + pos2) * 0.5f, ZeroVector, owner, false, false, false), pos1(pos1), pos2(pos2), orgSize(size), creationTime(gs->frameNum), lifeTime(time), color(color), dir1(dir1), dir2(dir2), drawTrail(drawTrail), drawSegmented(false), firstSegment(firstSegment), lastSegment(lastSegment), drawCallbacker(drawCallback), texture(texture == NULL ? projectileDrawer->smoketrailtex : texture) { checkCol = false; castShadow = true; if (!drawTrail) { const float dist = pos1.distance(pos2); dirpos1 = pos1 - dir1 * dist * 0.33f; dirpos2 = pos2 + dir2 * dist * 0.33f; } else if (dir1.dot(dir2) < 0.98f) { const float dist = pos1.distance(pos2); dirpos1 = pos1 - dir1 * dist * 0.33f; dirpos2 = pos2 + dir2 * dist * 0.33f; // float3 mp = (pos1 + pos2) / 2; midpos = CalcBeizer(0.5f, pos1, dirpos1, dirpos2, pos2); middir = (dir1 + dir2).ANormalize(); drawSegmented = true; } SetRadiusAndHeight(pos1.distance(pos2), 0.0f); if ((pos.y - CGround::GetApproximateHeight(pos.x, pos.z)) > 10) { useAirLos = true; } }
void CSound::PlaySample(size_t id, const float3& p, const float3& velocity, float volume, bool relative) { boost::mutex::scoped_lock lck(soundMutex); if (sources.empty() || volume == 0.0f) return; if (id == 0) { numEmptyPlayRequests++; return; } if (p.distance(myPos) > sounds[id].MaxDistance()) { if (!relative) return; else LogObject(LOG_SOUND) << "CSound::PlaySample: maxdist ignored for relative payback: " << sounds[id].Name(); } SoundSource* best = GetNextBestSource(false); if (!best->IsPlaying() || (best->GetCurrentPriority() <= 0 && best->GetCurrentPriority() < sounds[id].GetPriority())) best->Play(&sounds[id], p, velocity, volume, relative); CheckError("CSound::PlaySample"); }
int cCombatManager::GetClosestEnemy(float3 Pos, UnitInfo* U) { U->enemyID=-1; // these two function need improvement, for now I'll just use a short cut if( !G->UM->ActiveAttackOrders() && U->udrBL->task != TASK_SUICIDE ) return GetClosestThreat(Pos, U); sWeaponEfficiency* weTemp; float distance,fTemp; float3 fE; for( map<int,EnemyInfo>::iterator E=G->Enemies.begin(); E!=G->Enemies.end(); E++ ) { fE=GetEnemyPosition(E->first,&E->second); if( (weTemp = CanAttack(U,&E->second,fE)) != 0 ) { fTemp=Pos.distance(fE); if( U->enemyID == -1 || fTemp < distance ) { U->enemyID=E->first; U->E = &E->second; U->enemyEff = weTemp; distance=fTemp; } } } if( U->enemyID != -1 && U->group != 0 ) G->UM->GroupAddEnemy(U->enemyID,U->E,U->group); return U->enemyID; }
CLightingProjectile::CLightingProjectile(const float3& pos,const float3& end,CUnit* owner,const float3& color, WeaponDef *weaponDef,int ttl,CWeapon* weap) : CWeaponProjectile(pos,ZeroVector, owner, 0, ZeroVector, weaponDef,0), //CProjectile(pos,ZeroVector,owner), ttl(ttl), color(color), endPos(end), weapon(weap) { checkCol=false; drawRadius=pos.distance(endPos); displacements[0]=0; for(int a=1;a<10;++a) displacements[a]=(gs->randFloat()-0.5f)*drawRadius*0.05f; displacements2[0]=0; for(int a=1;a<10;++a) displacements2[a]=(gs->randFloat()-0.5f)*drawRadius*0.05f; if(weapon) AddDeathDependence(weapon); #ifdef TRACE_SYNC tracefile << "New lighting: "; tracefile << pos.x << " " << pos.y << " " << pos.z << " " << end.x << " " << end.y << " " << end.z << "\n"; #endif }
bool CTransportCAI::FindEmptyDropSpots(float3 startpos, float3 endpos, std::list<float3>& dropSpots) { //should only be used by air CTransportUnit* transport=(CTransportUnit*)owner; //dropSpots.clear(); float gap = 25.5; //TODO - set tag for this? float3 dir = endpos - startpos; dir.Normalize(); float3 nextPos = startpos; float3 pos; list<CTransportUnit::TransportedUnit>::iterator ti = transport->transported.begin(); dropSpots.push_front(nextPos); //first spot if (ti!=transport->transported.end()) { //float3 p = nextPos; //test to make intended land spots visible //inMapDrawer->CreatePoint(p,ti->unit->unitDef->name); //p.z +=transport->transportCapacityUsed*5; nextPos += dir*(gap + ti->unit->radius); ti++; } //remaining spots if (dynamic_cast<CTAAirMoveType*>(owner->moveType)) { while (ti != transport->transported.end() && startpos.distance(nextPos) < startpos.distance(endpos)) { nextPos += dir*(ti->unit->radius); nextPos.y = ground->GetHeight(nextPos.x, nextPos.z); //check landing spot is ok for landing on if (!SpotIsClear(nextPos,ti->unit)) continue; dropSpots.push_front(nextPos); //float3 p = nextPos; //test to make intended land spots visible //inMapDrawer->CreatePoint(p,ti->unit->unitDef->name); //p.z +=transport->transportCapacityUsed*5; nextPos += dir*(gap + ti->unit->radius); ti++; } return true; } return false; }
CMissileProjectile::CMissileProjectile(const float3& pos,const float3& speed,CUnit* owner,const DamageArray& damages,float areaOfEffect,float maxSpeed, int ttl,CUnit* target, WeaponDef *weaponDef,float3 targetPos) : CWeaponProjectile(pos,speed,owner,target,ZeroVector,weaponDef,0), damages(damages), ttl(ttl), maxSpeed(maxSpeed), target(target), dir(speed), oldSmoke(pos), age(0), drawTrail(true), numParts(0), areaOfEffect(areaOfEffect), decoyTarget(0), targPos(targetPos), wobbleTime(1), wobbleDir(0,0,0), wobbleDif(0,0,0), isWobbling(weaponDef->wobble>0), extraHeightTime(0) { curSpeed=speed.Length(); dir.Normalize(); oldDir=dir; if(target) AddDeathDependence(target); SetRadius(0.0); if(!weaponDef->visuals.modelName.empty()){ S3DOModel* model = modelParser->Load3DO(string("objects3d/")+weaponDef->visuals.modelName,1,0); if(model){ SetRadius(model->radius); } } drawRadius=radius+maxSpeed*8; ENTER_MIXED; float3 camDir=(pos-camera->pos).Normalize(); if(camera->pos.distance(pos)*0.2+(1-fabs(camDir.dot(dir)))*3000 < 200) drawTrail=false; ENTER_SYNCED; castShadow=true; #ifdef TRACE_SYNC tracefile << "New missile: "; tracefile << pos.x << " " << pos.y << " " << pos.z << " " << speed.x << " " << speed.y << " " << speed.z << "\n"; #endif if(target) target->IncomingMissile(this); if(weaponDef->trajectoryHeight>0){ float dist=pos.distance(targPos); extraHeight=dist*weaponDef->trajectoryHeight; if(dist<maxSpeed) dist=maxSpeed; extraHeightTime=(int)(dist/*+pos.distance(targPos+UpVector*dist))*0.5*//maxSpeed); extraHeightDecay=extraHeight/extraHeightTime; } }
CSmokeTrailProjectile::CSmokeTrailProjectile(const float3& pos1,const float3& pos2,const float3& dir1,const float3& dir2, CUnit* owner,bool firstSegment,bool lastSegment,float size,float time,float color,bool drawTrail,CProjectile* drawCallback) : CProjectile((pos1+pos2)*0.5f,ZeroVector,owner, false), pos1(pos1), pos2(pos2), creationTime(gs->frameNum), lifeTime((int)time), orgSize(size), color(color), dir1(dir1), dir2(dir2), drawTrail(drawTrail), drawSegmented(false), drawCallbacker(drawCallback), firstSegment(firstSegment), lastSegment(lastSegment) { checkCol=false; castShadow=true; if(!drawTrail){ float dist=pos1.distance(pos2); dirpos1=pos1-dir1*dist*0.33f; dirpos2=pos2+dir2*dist*0.33f; } else if(dir1.dot(dir2)<0.98f){ float dist=pos1.distance(pos2); dirpos1=pos1-dir1*dist*0.33f; dirpos2=pos2+dir2*dist*0.33f; float3 mp=(pos1+pos2)/2; midpos=CalcBeizer(0.5f,pos1,dirpos1,dirpos2,pos2); middir=(dir1+dir2).Normalize(); drawSegmented=true; } SetRadius(pos1.distance(pos2)); if(pos.y-ground->GetApproximateHeight(pos.x,pos.z)>10) useAirLos=true; }
void CSound::PlaySample(size_t id, const float3& p, const float3& velocity, float volume, bool relative) { GML_RECMUTEX_LOCK(sound); // PlaySample if (sources.empty() || volume == 0.0f) return; if (id == 0) { numEmptyPlayRequests++; return; } if (p.distance(myPos) > sounds[id].MaxDistance()) { if (!relative) return; else LogObject(LOG_SOUND) << "CSound::PlaySample: maxdist ignored for relative payback: " << sounds[id].Name(); } bool found1Free = false; int minPriority = 1; size_t minPos = 0; for (size_t pos = 0; pos != sources.size(); ++pos) { if (!sources[pos].IsPlaying()) { minPos = pos; found1Free = true; break; } else { if (sources[pos].GetCurrentPriority() < minPriority && sources[pos].GetCurrentPriority() <= sounds[id].GetPriority()) { found1Free = true; minPriority = sources[pos].GetCurrentPriority(); minPos = pos; } } } if (found1Free) sources[minPos].Play(&sounds[id], p, velocity, volume, relative); CheckError("CSound::PlaySample"); }
CGeoSquareProjectile::CGeoSquareProjectile(const float3& p1,const float3& p2,const float3& v1,const float3& v2,float w1,float w2) : CProjectile((p1+p2)*0.5f,ZeroVector,0, false), p1(p1), p2(p2), v1(v1), v2(v2), w1(w1), w2(w2), r(0.5f), g(1.0f), b(0.5f), a(0.5f) { checkCol=false; alwaysVisible=true; SetRadius(p1.distance(p2)*0.55f); }
void AudioChannel::FindSourceAndPlay(size_t id, const float3& pos, const float3& velocity, float volume, bool relative) { if (!enabled) return; if (volume <= 0.0f) return; boost::recursive_mutex::scoped_lock slck(soundMutex); SoundItem* sndItem = sound->GetSoundItem(id); if (!sndItem) { sound->numEmptyPlayRequests++; return; } if (pos.distance(sound->GetListenerPos()) > sndItem->MaxDistance()) { if (!relative) return; else LogObject(LOG_SOUND) << "CSound::PlaySample: maxdist ignored for relative payback: " << sndItem->Name(); } if (emmitsThisFrame >= emmitsPerFrame) return; emmitsThisFrame++; CSoundSource* sndSource = sound->GetNextBestSource(); if (!sndSource) return; if (sndSource->GetCurrentPriority() < sndItem->GetPriority()) { if (sndSource->IsPlaying()) sound->numAbortedPlays++; sndSource->Play(this, sndItem, pos, velocity, volume, relative); CheckError("CSound::FindSourceAndPlay"); boost::recursive_mutex::scoped_lock lck(chanMutex); cur_sources[sndSource] = true; } }
int cCombatManager::GetClosestThreat(float3 Pos, UnitInfo* U) { sWeaponEfficiency* weTemp; float distance,fTemp; distance=0.0f; float3 fE; set<int> deletion; for( map<int,EnemyInfo*>::iterator E=G->EThreat.begin(); E!=G->EThreat.end(); ++E ) { fE=GetEnemyPosition(E->first,E->second); if( E->second->baseThreatFrame > cb->GetCurrentFrame()+3600 || (E->second->baseThreatFrame > cb->GetCurrentFrame()+1200 && G->UImmobile.find(E->second->baseThreatID) == G->UImmobile.end() ) || (E->second->ud != 0 && G->UImmobile.find(E->second->baseThreatID) != G->UImmobile.end() && 1.3*E->second->ud->maxWeaponRange < fE.distance(cb->GetUnitPos(E->second->baseThreatID)) ) ) { E->second->baseThreatID = -1; E->second->baseThreatFrame = -1; deletion.insert(E->first); } else if( (weTemp = CanAttack(U,E->second,fE)) != 0 ) { fTemp=Pos.distance(fE); if( U->enemyID == -1 || fTemp < distance ) { U->enemyID=E->first; U->E = E->second; U->enemyEff = weTemp; distance=fTemp; } } } while( int(deletion.size()) > 0 ) { if( !G->UM->ActiveAttackOrders() ) { EnemyInfo* E = G->EThreat.find(*deletion.begin())->second; while( int(E->attackGroups.size()) > 0 ) G->UM->GroupRemoveEnemy(*deletion.begin(),E,*E->attackGroups.begin()); } G->EThreat.erase(*deletion.begin()); deletion.erase(*deletion.begin()); } if( U->enemyID != -1 && U->group != 0 ) G->UM->GroupAddEnemy(U->enemyID,U->E,U->group); return U->enemyID; }
CLightningProjectile::CLightningProjectile( const float3& pos, const float3& end, CUnit* owner, const float3& color, const WeaponDef* weaponDef, int ttl, CWeapon* weap): CWeaponProjectile(pos, ZeroVector, owner, 0, ZeroVector, weaponDef, 0, ttl), color(color), endPos(end), weapon(weap) { projectileType = WEAPON_LIGHTNING_PROJECTILE; checkCol = false; drawRadius = pos.distance(endPos); displacements[0]=0; for(int a=1;a<10;++a) displacements[a]=(gs->randFloat()-0.5f)*drawRadius*0.05f; displacements2[0]=0; for(int a=1;a<10;++a) displacements2[a]=(gs->randFloat()-0.5f)*drawRadius*0.05f; if(weapon) AddDeathDependence(weapon); #ifdef TRACE_SYNC tracefile << "New lightning: "; tracefile << pos.x << " " << pos.y << " " << pos.z << " " << end.x << " " << end.y << " " << end.z << "\n"; #endif if (!cegTag.empty()) { ceg.Load(explGenHandler, cegTag); } }
CLightningProjectile::CLightningProjectile( const float3& pos, const float3& end, CUnit* owner, const float3& color, const WeaponDef* weaponDef, int ttl, CWeapon* weap) : CWeaponProjectile(pos, ZeroVector, owner, NULL, ZeroVector, weaponDef, NULL, ttl) , color(color) , endPos(end) , weapon(weap) { projectileType = WEAPON_LIGHTNING_PROJECTILE; checkCol = false; drawRadius = pos.distance(endPos); displacements[0] = 0.0f; for (size_t d = 1; d < displacements_size; ++d) { displacements[d] = (gs->randFloat() - 0.5f) * drawRadius * 0.05f; } displacements2[0] = 0.0f; for (size_t d = 1; d < displacements_size; ++d) { displacements2[d] = (gs->randFloat() - 0.5f) * drawRadius * 0.05f; } if (weapon) { AddDeathDependence(weapon); } #ifdef TRACE_SYNC tracefile << "New lightning: "; tracefile << pos.x << " " << pos.y << " " << pos.z << " " << end.x << " " << end.y << " " << end.z << "\n"; #endif cegID = gCEG->Load(explGenHandler, cegTag); }
void AudioChannel::FindSourceAndPlay(size_t id, const float3& pos, const float3& velocity, float volume, bool relative) { std::lock_guard<spring::recursive_mutex> lck(soundMutex); if (!enabled) return; if (volume <= 0.0f) return; // generate the sound item SoundItem* sndItem = sound->GetSoundItem(id); if (sndItem == nullptr) { sound->numEmptyPlayRequests++; return; } // check distance to listener if (pos.distance(sound->GetListenerPos()) > sndItem->MaxDistance()) { if (!relative) return; LOG("CSound::PlaySample: maxdist ignored for relative playback: %s", sndItem->Name().c_str()); } // don't spam to many sounds per frame if (emitsThisFrame >= emitsPerFrame) return; emitsThisFrame++; // check if the sound item is already played if (curSources.size() >= maxConcurrentSources) { CSoundSource* src = nullptr; int prio = INT_MAX; for (auto it = curSources.begin(); it != curSources.end(); ++it) { if ((*it)->GetCurrentPriority() < prio) { src = *it; prio = src->GetCurrentPriority(); } } if (src == nullptr || prio > sndItem->GetPriority()) { LOG_L(L_DEBUG, "CSound::PlaySample: Max concurrent sounds in channel reached! Dropping playback!"); return; } src->Stop(); } // find a sound source to play the item in CSoundSource* sndSource = sound->GetNextBestSource(); if (sndSource == nullptr || (sndSource->GetCurrentPriority() >= sndItem->GetPriority())) { LOG_L(L_DEBUG, "CSound::PlaySample: Max sounds reached! Dropping playback!"); return; } if (sndSource->IsPlaying()) sound->numAbortedPlays++; // play the sound item sndSource->PlayAsync(this, sndItem, pos, velocity, volume, relative); curSources.insert(sndSource); }
// problems: giving reclaim order on moving target causes commander // to walk (messing up subsequent dgun order if target still moving) // and does not take commander torso rotation time into account // void CDGunController::TrackAttackTarget(unsigned int currentFrame) { if (currentFrame - state.targetSelectionFrame == 5) { // five sim-frames have passed since selecting target, attack const UnitDef* udef = ai->cb->GetUnitDef(state.targetID); const float3 curTargetPos = ai->cb->GetUnitPos(state.targetID); // current target position const float3 commanderPos = ai->cb->GetUnitPos(commanderID); // current commander position const float3 targetDif = (commanderPos - curTargetPos); const float targetDist = targetDif.Length(); // distance to target const float3 targetVel = (curTargetPos - state.oldTargetPos); float3 targetMoveDir = targetVel; float targetMoveSpeed = 0.0f; if (targetVel != ZeroVector) { targetMoveSpeed = targetVel.Length() / 5.0f; // target speed per sim-frame during tracking interval targetMoveDir = targetVel / (targetMoveSpeed * 5.0f); // target direction of movement } const float dgunDelay = targetDist / commanderWD->projectilespeed; // sim-frames needed for dgun to reach target position const float3 leadPos = targetMoveDir * (targetMoveSpeed * dgunDelay); const float3 dgunPos = curTargetPos + leadPos; // position where target will be in <dgunDelay> frames const float maxRange = ai->cb->GetUnitMaxRange(commanderID); bool haveClearShot = true; int orderType = -1; AIHCTraceRay rayData = { commanderPos, targetDif / targetDist, // direction maxRange, commanderID, -1, 0 }; ai->cb->HandleCommand(AIHCTraceRayId, &rayData); if (rayData.hitUID != -1) { // note: still fails when allied structure is between us and enemy // can also fail if enemy is in front of allied structure and both // are within the d-gun's range haveClearShot = (ai->cb->GetUnitAllyTeam(rayData.hitUID) != ai->cb->GetMyAllyTeam()); // TODO: get DGun weapon properties & check if it can pass through // a unit, if yes then allow executing the code below if(haveClearShot) { // check if there is a unit next to hit unit on DGun path... const float3 enemyPos = ai->cb->GetUnitPos(rayData.hitUID); const float segmentLeft = maxRange - commanderPos.distance(enemyPos); if(segmentLeft > 0.0) { AIHCTraceRay rayData2 = { enemyPos, targetDif / targetDist, segmentLeft, rayData.hitUID, -1, 0 }; ai->cb->HandleCommand(AIHCTraceRayId, &rayData2); if(rayData2.hitUID != -1) { haveClearShot = (ai->cb->GetUnitAllyTeam(rayData2.hitUID) != ai->cb->GetMyAllyTeam()); } } } } // multiply by 0.9 to ensure commander does not have to walk if ((commanderPos - dgunPos).Length() < maxRange * 0.9f) { bool canDGun = (ai->cb->GetEnergy() >= DGUN_MIN_ENERGY_LEVEL) && haveClearShot && (udef != NULL && !udef->weapons.empty()); if(canDGun) { IssueOrder(dgunPos, orderType = CMD_DGUN, 0); } else { bool bDanger = ai->tm->ThreatAtThisPoint(commanderPos/*curTargetPos*/) > ai->tm->GetAverageThreat(); if(bDanger) { state.Reset(currentFrame, true); } else { if (ai->cb->GetUnitHealth(state.targetID) < ai->cb->GetUnitMaxHealth(state.targetID) * 0.5f) { IssueOrder(state.targetID, orderType = CMD_RECLAIM, 0); } else { IssueOrder(state.targetID, orderType = CMD_CAPTURE, 0); } } } if (orderType == CMD_DGUN ) { state.dgunOrderFrame = ai->cb->GetCurrentFrame(); } if (orderType == CMD_RECLAIM) { state.reclaimOrderFrame = ai->cb->GetCurrentFrame(); } if (orderType == CMD_CAPTURE) { state.captureOrderFrame = ai->cb->GetCurrentFrame(); } } else { state.Reset(currentFrame, true); } } state.Reset(currentFrame, false); }
void CAdvTreeDrawer::DrawShadowPass(void) { const float treeDistance = oldTreeDistance; const int activeFarTex = (camera->forward.z < 0.0f)? treeGen->farTex[0] : treeGen->farTex[1]; const bool drawDetailed = (treeDistance >= 4.0f); glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, activeFarTex); glEnable(GL_TEXTURE_2D); glEnable(GL_ALPHA_TEST); glDisable(GL_CULL_FACE); glPolygonOffset(1, 1); glEnable(GL_POLYGON_OFFSET_FILL); CAdvTreeSquareDrawer_SP drawer; const int cx = drawer.cx = (int)(camera->pos.x / (SQUARE_SIZE * TREE_SQUARE_SIZE)); const int cy = drawer.cy = (int)(camera->pos.z / (SQUARE_SIZE * TREE_SQUARE_SIZE)); drawer.drawDetailed = drawDetailed; drawer.td = this; drawer.treeDistance = treeDistance * SQUARE_SIZE * TREE_SQUARE_SIZE; Shader::IProgramObject* po = NULL; GML_STDMUTEX_LOCK(tree); // DrawShadowPass // draw with extraSize=1 readmap->GridVisibility(camera, TREE_SQUARE_SIZE, drawer.treeDistance * 2.0f, &drawer, 1); if (drawDetailed) { const int xstart = std::max( 0, cx - 2); const int xend = std::min(gs->mapx / TREE_SQUARE_SIZE - 1, cx + 2); const int ystart = std::max( 0, cy - 2); const int yend = std::min(gs->mapy / TREE_SQUARE_SIZE - 1, cy + 2); glBindTexture(GL_TEXTURE_2D, treeGen->barkTex); glEnable(GL_TEXTURE_2D); po = shadowHandler->GetShadowGenProg(CShadowHandler::SHADOWGEN_PROGRAM_TREE_NEAR); po->Enable(); if (globalRendering->haveGLSL) { po->SetUniform3fv(1, &camera->right[0]); po->SetUniform3fv(2, &camera->up[0]); } else { po->SetUniformTarget(GL_VERTEX_PROGRAM_ARB); po->SetUniform4f(13, camera->right.x, camera->right.y, camera->right.z, 0.0f); po->SetUniform4f(9, camera->up.x, camera->up.y, camera->up.z, 0.0f); po->SetUniform4f(11, 1.0f, 1.0f, 1.0f, 0.85f ); po->SetUniform4f(12, 0.0f, 0.0f, 0.0f, 0.20f * (1.0f / MAX_TREE_HEIGHT)); // w = alpha/height modifier } glAlphaFunc(GL_GREATER, 0.5f); glEnable(GL_ALPHA_TEST); glColor4f(1.0f, 1.0f, 1.0f, 1.0f); varr = GetVertexArray(); varr->Initialize(); static FadeTree fadeTrees[3000]; FadeTree* pFT = fadeTrees; for (TreeSquareStruct* pTSS = trees + ystart * treesX; pTSS <= trees + yend * treesX; pTSS += treesX) { for (TreeSquareStruct* tss = pTSS + xstart; tss <= pTSS + xend; ++tss) { tss->lastSeen = gs->frameNum; varr->EnlargeArrays(12 * tss->trees.size(), 0, VA_SIZE_T); //!alloc room for all tree vertexes for (std::map<int, TreeStruct>::iterator ti = tss->trees.begin(); ti != tss->trees.end(); ++ti) { const TreeStruct* ts = &ti->second; const float3 pos(ts->pos); if (!camera->InView(pos + float3(0, MAX_TREE_HEIGHT / 2, 0), MAX_TREE_HEIGHT / 2 + 150)) { continue; } const float camDist = (pos - camera->pos).SqLength(); int type = ts->type; float dy = 0.0f; unsigned int displist; if (type < 8) { dy = 0.5f; displist = treeGen->pineDL + type; } else { type -= 8; dy = 0; displist = treeGen->leafDL + type; } if (camDist < SQUARE_SIZE * SQUARE_SIZE * 110 * 110) { po->SetUniform3f((globalRendering->haveGLSL? 3: 10), pos.x, pos.y, pos.z); glCallList(displist); } else if (camDist < SQUARE_SIZE * SQUARE_SIZE * 125 * 125) { const float relDist = (pos.distance(camera->pos) - SQUARE_SIZE * 110) / (SQUARE_SIZE * 15); glAlphaFunc(GL_GREATER, 0.8f + relDist * 0.2f); po->SetUniform3f((globalRendering->haveGLSL? 3: 10), pos.x, pos.y, pos.z); glCallList(displist); glAlphaFunc(GL_GREATER, 0.5f); pFT->pos = pos; pFT->deltaY = dy; pFT->type = type; pFT->relDist = relDist; ++pFT; } else { DrawTreeVertex(varr, pos, type * 0.125f, dy, false); } } } } po->SetUniform3f((globalRendering->haveGLSL? 3: 10), 0.0f, 0.0f, 0.0f); for (std::list<FallingTree>::iterator fti = fallingTrees.begin(); fti != fallingTrees.end(); ++fti) { const float3 pos = fti->pos - UpVector * (fti->fallPos * 20); if (camera->InView(pos + float3(0, MAX_TREE_HEIGHT / 2, 0), MAX_TREE_HEIGHT / 2)) { const float ang = fti->fallPos * PI; const float3 yvec(fti->dir.x * sin(ang), cos(ang), fti->dir.z * sin(ang)); const float3 zvec((yvec.cross(float3(1.0f, 0.0f, 0.0f))).ANormalize()); const float3 xvec(zvec.cross(yvec)); CMatrix44f transMatrix(pos, xvec, yvec, zvec); glPushMatrix(); glMultMatrixf(&transMatrix[0]); int type = fti->type; int displist; if (type < 8) { displist = treeGen->pineDL + type; } else { type -= 8; displist = treeGen->leafDL + type; } glCallList(displist); glPopMatrix(); } } po->Disable(); po = shadowHandler->GetShadowGenProg(CShadowHandler::SHADOWGEN_PROGRAM_TREE_FAR); po->Enable(); glBindTexture(GL_TEXTURE_2D, activeFarTex); varr->DrawArrayT(GL_QUADS); for (FadeTree* pFTree = fadeTrees; pFTree < pFT; ++pFTree) { // faded close trees varr = GetVertexArray(); varr->Initialize(); varr->CheckInitSize(12 * VA_SIZE_T); DrawTreeVertex(varr, pFTree->pos, pFTree->type * 0.125f, pFTree->deltaY, false); glAlphaFunc(GL_GREATER, 1.0f - (pFTree->relDist * 0.5f)); varr->DrawArrayT(GL_QUADS); } po->Disable(); } glEnable(GL_CULL_FACE); glDisable(GL_POLYGON_OFFSET_FILL); glDisable(GL_TEXTURE_2D); glDisable(GL_ALPHA_TEST); }
CMissileProjectile::CMissileProjectile( const float3& pos, const float3& speed, CUnit* owner, float areaOfEffect, float maxSpeed, int ttl, CUnit* target, const WeaponDef* weaponDef, float3 targetPos) : CWeaponProjectile(pos, speed, owner, target, targetPos, weaponDef, NULL, ttl) , maxSpeed(maxSpeed) , areaOfEffect(areaOfEffect) , age(0) , oldSmoke(pos) , target(target) , decoyTarget(NULL) , drawTrail(true) , numParts(0) , targPos(targetPos) , isWobbling(weaponDef? (weaponDef->wobble > 0): false) , wobbleDir(ZeroVector) , wobbleTime(1) , wobbleDif(ZeroVector) , isDancing(weaponDef? (weaponDef->dance > 0): false) , danceTime(1) , danceMove(ZeroVector) , danceCenter(ZeroVector) , extraHeightTime(0) { projectileType = WEAPON_MISSILE_PROJECTILE; curSpeed = speed.Length(); dir = speed / curSpeed; oldDir = dir; if (target) { AddDeathDependence(target); } SetRadius(0.0f); if (weaponDef) { model = LoadModel(weaponDef); if (model) { SetRadius(model->radius); } } drawRadius = radius + maxSpeed * 8; float3 camDir = (pos - camera->pos).Normalize(); if ((camera->pos.distance(pos) * 0.2f + (1 - fabs(camDir.dot(dir))) * 3000) < 200) { drawTrail = false; } castShadow = true; #ifdef TRACE_SYNC tracefile << "New missile: "; tracefile << pos.x << " " << pos.y << " " << pos.z << " " << speed.x << " " << speed.y << " " << speed.z << "\n"; #endif if (target) { target->IncomingMissile(this); } if ((weaponDef) && (weaponDef->trajectoryHeight > 0)) { float dist = pos.distance(targPos); extraHeight = (dist * weaponDef->trajectoryHeight); if (dist < maxSpeed) { dist = maxSpeed; } extraHeightTime = (int)(dist / maxSpeed); extraHeightDecay = extraHeight / extraHeightTime; } cegID = gCEG->Load(explGenHandler, cegTag); }
void CAdvTreeDrawer::Draw(float treeDistance, bool drawReflection) { const int activeFarTex = (camera->forward.z < 0.0f)? treeGen->farTex[0]: treeGen->farTex[1]; const bool drawDetailed = ((treeDistance >= 4.0f) || drawReflection); CBaseGroundDrawer* gd = readmap->GetGroundDrawer(); Shader::IProgramObject* treeShader = NULL; #define L mapInfo->light glEnable(GL_ALPHA_TEST); glEnable(GL_TEXTURE_2D); if (globalRendering->drawFog) { glFogfv(GL_FOG_COLOR, mapInfo->atmosphere.fogColor); glEnable(GL_FOG); } if (shadowHandler->shadowsLoaded && !gd->DrawExtraTex()) { glActiveTexture(GL_TEXTURE1); glBindTexture(GL_TEXTURE_2D, activeFarTex); glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, shadowHandler->shadowTexture); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE_ARB, GL_COMPARE_R_TO_TEXTURE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_FUNC_ARB, GL_LEQUAL); glTexParameteri(GL_TEXTURE_2D, GL_DEPTH_TEXTURE_MODE_ARB, GL_ALPHA); treeShader = treeShaders[TREE_PROGRAM_DIST_SHADOW]; treeShader->Enable(); if (globalRendering->haveGLSL) { treeShader->SetUniformMatrix4fv(7, false, &shadowHandler->shadowMatrix.m[0]); treeShader->SetUniform4fv(8, &(shadowHandler->GetShadowParams().x)); } else { treeShader->SetUniformTarget(GL_FRAGMENT_PROGRAM_ARB); treeShader->SetUniform4f(10, L.groundAmbientColor.x, L.groundAmbientColor.y, L.groundAmbientColor.z, 1.0f); treeShader->SetUniform4f(11, 0.0f, 0.0f, 0.0f, 1.0f - (sky->GetLight()->GetGroundShadowDensity() * 0.5f)); treeShader->SetUniformTarget(GL_VERTEX_PROGRAM_ARB); glMatrixMode(GL_MATRIX0_ARB); glLoadMatrixf(shadowHandler->shadowMatrix.m); glMatrixMode(GL_MODELVIEW); } } else { glBindTexture(GL_TEXTURE_2D, activeFarTex); } const int cx = int(camera->pos.x / (SQUARE_SIZE * TREE_SQUARE_SIZE)); const int cy = int(camera->pos.z / (SQUARE_SIZE * TREE_SQUARE_SIZE)); CAdvTreeSquareDrawer drawer(this, cx, cy, treeDistance * SQUARE_SIZE * TREE_SQUARE_SIZE, drawDetailed); GML_STDMUTEX_LOCK(tree); // Draw oldTreeDistance = treeDistance; // draw far-trees using map-dependent grid-visibility readmap->GridVisibility(camera, TREE_SQUARE_SIZE, drawer.treeDistance * 2.0f, &drawer); if (drawDetailed) { // draw near-trees const int xstart = std::max( 0, cx - 2); const int xend = std::min(gs->mapx / TREE_SQUARE_SIZE - 1, cx + 2); const int ystart = std::max( 0, cy - 2); const int yend = std::min(gs->mapy / TREE_SQUARE_SIZE - 1, cy + 2); if (shadowHandler->shadowsLoaded && !gd->DrawExtraTex()) { treeShader->Disable(); treeShader = treeShaders[TREE_PROGRAM_NEAR_SHADOW]; treeShader->Enable(); if (globalRendering->haveGLSL) { treeShader->SetUniformMatrix4fv(7, false, &shadowHandler->shadowMatrix.m[0]); treeShader->SetUniform4fv(8, &(shadowHandler->GetShadowParams().x)); } glActiveTexture(GL_TEXTURE1); glEnable(GL_TEXTURE_2D); glBindTexture(GL_TEXTURE_2D, treeGen->barkTex); glActiveTexture(GL_TEXTURE0); } else { glBindTexture(GL_TEXTURE_2D, treeGen->barkTex); treeShader = treeShaders[TREE_PROGRAM_NEAR_BASIC]; treeShader->Enable(); if (!globalRendering->haveGLSL) { #define MX (gs->pwr2mapx * SQUARE_SIZE) #define MY (gs->pwr2mapy * SQUARE_SIZE) treeShader->SetUniformTarget(GL_VERTEX_PROGRAM_ARB); treeShader->SetUniform4f(15, 1.0f / MX, 1.0f / MY, 1.0f / MX, 1.0f); #undef MX #undef MY } } if (globalRendering->haveGLSL) { treeShader->SetUniform3fv(0, &camera->right[0]); treeShader->SetUniform3fv(1, &camera->up[0]); treeShader->SetUniform2f(5, 0.20f * (1.0f / MAX_TREE_HEIGHT), 0.85f); } else { treeShader->SetUniformTarget(GL_VERTEX_PROGRAM_ARB); treeShader->SetUniform3f(13, camera->right.x, camera->right.y, camera->right.z); treeShader->SetUniform3f( 9, camera->up.x, camera->up.y, camera->up.z ); treeShader->SetUniform4f(11, L.groundSunColor.x, L.groundSunColor.y, L.groundSunColor.z, 0.85f); treeShader->SetUniform4f(14, L.groundAmbientColor.x, L.groundAmbientColor.y, L.groundAmbientColor.z, 0.85f); treeShader->SetUniform4f(12, 0.0f, 0.0f, 0.0f, 0.20f * (1.0f / MAX_TREE_HEIGHT)); // w = alpha/height modifier } glAlphaFunc(GL_GREATER, 0.5f); glDisable(GL_BLEND); glColor4f(1.0f, 1.0f, 1.0f, 1.0f); varr = GetVertexArray(); varr->Initialize(); static FadeTree fadeTrees[3000]; FadeTree* pFT = fadeTrees; for (TreeSquareStruct* pTSS = trees + ystart * treesX; pTSS <= trees + yend * treesX; pTSS += treesX) { for (TreeSquareStruct* tss = pTSS + xstart; tss <= pTSS + xend; ++tss) { tss->lastSeen = gs->frameNum; varr->EnlargeArrays(12 * tss->trees.size(), 0, VA_SIZE_T); //!alloc room for all tree vertexes for (std::map<int, TreeStruct>::iterator ti = tss->trees.begin(); ti != tss->trees.end(); ++ti) { const TreeStruct* ts = &ti->second; const float3 pos(ts->pos); if (!camera->InView(pos + float3(0.0f, MAX_TREE_HEIGHT / 2.0f, 0.0f), MAX_TREE_HEIGHT / 2.0f)) { continue; } const float camDist = (pos - camera->pos).SqLength(); int type = ts->type; float dy = 0.0f; unsigned int displist; if (type < 8) { dy = 0.5f; displist = treeGen->pineDL + type; } else { type -= 8; dy = 0.0f; displist = treeGen->leafDL + type; } if (camDist < (SQUARE_SIZE * SQUARE_SIZE * 110 * 110)) { // draw detailed near-distance tree (same as mid-distance trees without alpha) treeShader->SetUniform3f(((globalRendering->haveGLSL)? 2: 10), pos.x, pos.y, pos.z); glCallList(displist); } else if (camDist < (SQUARE_SIZE * SQUARE_SIZE * 125 * 125)) { // draw mid-distance tree const float relDist = (pos.distance(camera->pos) - SQUARE_SIZE * 110) / (SQUARE_SIZE * 15); treeShader->SetUniform3f(((globalRendering->haveGLSL)? 2: 10), pos.x, pos.y, pos.z); glAlphaFunc(GL_GREATER, 0.8f + relDist * 0.2f); glCallList(displist); glAlphaFunc(GL_GREATER, 0.5f); // save for second pass pFT->pos = pos; pFT->deltaY = dy; pFT->type = type; pFT->relDist = relDist; ++pFT; } else { // draw far-distance tree DrawTreeVertex(varr, pos, type * 0.125f, dy, false); } } } } // reset the world-offset treeShader->SetUniform3f(((globalRendering->haveGLSL)? 2: 10), 0.0f, 0.0f, 0.0f); // draw trees that have been marked as falling for (std::list<FallingTree>::iterator fti = fallingTrees.begin(); fti != fallingTrees.end(); ++fti) { const float3 pos = fti->pos - UpVector * (fti->fallPos * 20); if (camera->InView(pos + float3(0.0f, MAX_TREE_HEIGHT / 2, 0.0f), MAX_TREE_HEIGHT / 2.0f)) { const float ang = fti->fallPos * PI; const float3 yvec(fti->dir.x * sin(ang), cos(ang), fti->dir.z * sin(ang)); const float3 zvec((yvec.cross(float3(-1.0f, 0.0f, 0.0f))).ANormalize()); const float3 xvec(yvec.cross(zvec)); CMatrix44f transMatrix(pos, xvec, yvec, zvec); glPushMatrix(); glMultMatrixf(&transMatrix[0]); int type = fti->type; int displist = 0; if (type < 8) { displist = treeGen->pineDL + type; } else { type -= 8; displist = treeGen->leafDL + type; } glCallList(displist); glPopMatrix(); } } if (shadowHandler->shadowsLoaded && !gd->DrawExtraTex()) { treeShader->Disable(); treeShader = treeShaders[TREE_PROGRAM_DIST_SHADOW]; treeShader->Enable(); glActiveTexture(GL_TEXTURE1); glBindTexture(GL_TEXTURE_2D, activeFarTex); glActiveTexture(GL_TEXTURE0); } else { treeShader->Disable(); glBindTexture(GL_TEXTURE_2D, activeFarTex); } // draw far-distance trees varr->DrawArrayT(GL_QUADS); // draw faded mid-distance trees for (FadeTree* pFTree = fadeTrees; pFTree < pFT; ++pFTree) { varr = GetVertexArray(); varr->Initialize(); varr->CheckInitSize(12 * VA_SIZE_T); DrawTreeVertex(varr, pFTree->pos, pFTree->type * 0.125f, pFTree->deltaY, false); glAlphaFunc(GL_GREATER, 1.0f - (pFTree->relDist * 0.5f)); varr->DrawArrayT(GL_QUADS); } } if (shadowHandler->shadowsLoaded && !gd->DrawExtraTex()) { treeShader->Disable(); glActiveTexture(GL_TEXTURE1); glBindTexture(GL_TEXTURE_2D, 0); glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, 0); glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE_ARB, GL_NONE); glTexParameteri(GL_TEXTURE_2D, GL_DEPTH_TEXTURE_MODE_ARB, GL_LUMINANCE); } else { glBindTexture(GL_TEXTURE_2D, 0); } glDisable(GL_TEXTURE_2D); glDisable(GL_FOG); glDisable(GL_ALPHA_TEST); // clean out squares from memory that are no longer visible const int startClean = lastListClean * 20 % (nTrees); const int endClean = gs->frameNum * 20 % (nTrees); lastListClean = gs->frameNum; if (startClean > endClean) { for (TreeSquareStruct* pTSS = trees + startClean; pTSS < trees + nTrees; ++pTSS) { if ((pTSS->lastSeen < gs->frameNum - 50) && pTSS->displist) { glDeleteLists(pTSS->displist, 1); pTSS->displist = 0; } if ((pTSS->lastSeenFar < gs->frameNum - 50) && pTSS->farDisplist) { glDeleteLists(pTSS->farDisplist, 1); pTSS->farDisplist = 0; } } for (TreeSquareStruct* pTSS = trees; pTSS < trees + endClean; ++pTSS) { if ((pTSS->lastSeen < gs->frameNum - 50) && pTSS->displist) { glDeleteLists(pTSS->displist, 1); pTSS->displist = 0; } if ((pTSS->lastSeenFar < gs->frameNum - 50) && pTSS->farDisplist) { glDeleteLists(pTSS->farDisplist, 1); pTSS->farDisplist = 0; } } } else { for (TreeSquareStruct* pTSS = trees + startClean; pTSS < trees + endClean; ++pTSS) { if ((pTSS->lastSeen < gs->frameNum - 50) && pTSS->displist) { glDeleteLists(pTSS->displist, 1); pTSS->displist = 0; } if ((pTSS->lastSeenFar < gs->frameNum - 50) && pTSS->farDisplist) { glDeleteLists(pTSS->farDisplist, 1); pTSS->farDisplist = 0; } } } #undef L }
static inline float LineGroundSquareCol( const float* heightmap, const float3* normalmap, const float3& from, const float3& to, const int xs, const int ys) { const bool inMap = (xs >= 0) && (ys >= 0) && (xs <= mapDims.mapxm1) && (ys <= mapDims.mapym1); // assert(inMap); if (!inMap) return -1.0f; // The terrain grid is "composed" of two right-isosceles triangles // per square, so we have to check both faces (triangles) whether an // intersection exists // for each triangle, we pick one representative vertex // top-left corner vertex { float3 cornerVertex; cornerVertex.x = xs * SQUARE_SIZE; cornerVertex.z = ys * SQUARE_SIZE; cornerVertex.y = heightmap[ys * mapDims.mapxp1 + xs]; // project \<to - cornerVertex\> vector onto the TL-normal // if \<to\> lies below the terrain, this will be negative const float3 faceNormalTL = normalmap[(ys * mapDims.mapx + xs) * 2 ]; float toFacePlaneDist = (to - cornerVertex).dot(faceNormalTL); if (toFacePlaneDist <= 0.0f) { // project \<from - cornerVertex\> onto the TL-normal float fromFacePlaneDist = (from - cornerVertex).dot(faceNormalTL); if (fromFacePlaneDist != toFacePlaneDist) { const float alpha = fromFacePlaneDist / (fromFacePlaneDist - toFacePlaneDist); const float3 col = mix(from, to, alpha); if ((col.x >= cornerVertex.x) && (col.z >= cornerVertex.z) && (col.x + col.z <= cornerVertex.x + cornerVertex.z + SQUARE_SIZE)) { // point of intersection is inside the TL triangle return col.distance(from); } } } } // bottom-right corner vertex { float3 cornerVertex; cornerVertex.x = (xs + 1) * SQUARE_SIZE; cornerVertex.z = (ys + 1) * SQUARE_SIZE; cornerVertex.y = heightmap[(ys + 1) * mapDims.mapxp1 + (xs + 1)]; // project \<to - cornerVertex\> vector onto the TL-normal // if \<to\> lies below the terrain, this will be negative const float3 faceNormalBR = normalmap[(ys * mapDims.mapx + xs) * 2 + 1]; float toFacePlaneDist = (to - cornerVertex).dot(faceNormalBR); if (toFacePlaneDist <= 0.0f) { // project \<from - cornerVertex\> onto the BR-normal float fromFacePlaneDist = (from - cornerVertex).dot(faceNormalBR); if (fromFacePlaneDist != toFacePlaneDist) { const float alpha = fromFacePlaneDist / (fromFacePlaneDist - toFacePlaneDist); const float3 col = mix(from, to, alpha); if ((col.x <= cornerVertex.x) && (col.z <= cornerVertex.z) && (col.x + col.z >= cornerVertex.x + cornerVertex.z - SQUARE_SIZE)) { // point of intersection is inside the BR triangle return col.distance(from); } } } } return -2.0f; }
float CGround::LineGroundCol(float3 from, float3 to, bool synced) { const float* hm = readMap->GetSharedCornerHeightMap(synced); const float3* nm = readMap->GetSharedFaceNormals(synced); const float3 pfrom = from; // only for performance -> skip part that can impossibly collide // with the terrain, cause it is above map's current max height ClampInMapHeight(from, to); // handle special cases where the ray origin is out of bounds: // need to move <from> to the closest map-edge along the ray // (if both <from> and <to> are out of bounds, the ray might // still hit) // clamping <from> naively would change the direction of the // ray, hence we save the distance along it that got skipped ClampLineInMap(from, to); if (from == to) { // ClampLineInMap & ClampInMapHeight set `from == to == vec(-1,-1,-1)` // in case the line is outside of the map return -1.0f; } const float skippedDist = pfrom.distance(from); if (synced) { //TODO do this in unsynced too once the map border rendering is finished? // check if our start position is underground (assume ground is unpassable for cannons etc.) const int sx = from.x / SQUARE_SIZE; const int sz = from.z / SQUARE_SIZE; if (from.y <= hm[sz * mapDims.mapxp1 + sx]) { return 0.0f + skippedDist; } } const float dx = to.x - from.x; const float dz = to.z - from.z; const int dirx = (dx > 0.0f) ? 1 : -1; const int dirz = (dz > 0.0f) ? 1 : -1; // Clamping is done cause LineGroundSquareCol() operates on the 2 triangles faces each heightmap // square is formed of. const float ffsx = Clamp(from.x / SQUARE_SIZE, 0.0f, (float)mapDims.mapx); const float ffsz = Clamp(from.z / SQUARE_SIZE, 0.0f, (float)mapDims.mapy); const float ttsx = Clamp(to.x / SQUARE_SIZE, 0.0f, (float)mapDims.mapx); const float ttsz = Clamp(to.z / SQUARE_SIZE, 0.0f, (float)mapDims.mapy); const int fsx = ffsx; const int fsz = ffsz; const int tsx = ttsx; const int tsz = ttsz; bool keepgoing = true; if ((fsx == tsx) && (fsz == tsz)) { // <from> and <to> are the same const float ret = LineGroundSquareCol(hm, nm, from, to, fsx, fsz); if (ret >= 0.0f) { return (ret + skippedDist); } } else if (fsx == tsx) { // ray is parallel to z-axis int zp = fsz; while (keepgoing) { const float ret = LineGroundSquareCol(hm, nm, from, to, fsx, zp); if (ret >= 0.0f) { return (ret + skippedDist); } keepgoing = (zp != tsz); zp += dirz; } } else if (fsz == tsz) { // ray is parallel to x-axis int xp = fsx; while (keepgoing) { const float ret = LineGroundSquareCol(hm, nm, from, to, xp, fsz); if (ret >= 0.0f) { return (ret + skippedDist); } keepgoing = (xp != tsx); xp += dirx; } } else { // general case const float rdsx = SQUARE_SIZE / dx; // := 1 / (dx / SQUARE_SIZE) const float rdsz = SQUARE_SIZE / dz; // we need to shift the `test`-point in case of negative directions // case: dir<0 // ___________ // | | | | // |___|___|___| // ^cur // ^cur + dir // > < range of int(cur + dir) // ^wanted test point := cur - epsilon // you can set epsilon=0 and then handle the `beyond end`-case (xn >= 1.0f && zn >= 1.0f) separate // (we already need to do so cause of floating point precision limits, so skipping epsilon doesn't add // any additional performance cost nor precision issue) // // case : dir>0 // in case of `dir>0` the wanted test point is idential with `cur + dir` const float testposx = (dx > 0.0f) ? 0.0f : 1.0f; const float testposz = (dz > 0.0f) ? 0.0f : 1.0f; int curx = fsx; int curz = fsz; while (keepgoing) { // do the collision test with the squares triangles const float ret = LineGroundSquareCol(hm, nm, from, to, curx, curz); if (ret >= 0.0f) { return (ret + skippedDist); } // check if we reached the end already and need to stop the loop const bool endReached = (curx == tsx && curz == tsz); const bool beyondEnd = ((curx - tsx) * dirx > 0) || ((curz - tsz) * dirz > 0); assert(!beyondEnd); keepgoing = !endReached && !beyondEnd; if (!keepgoing) break; // calculate the `normalized position` of the next edge in x & z direction // `normalized position`:=n : x = from.x + n * (to.x - from.x) (with 0<= n <=1) int nextx = curx + dirx; int nextz = curz + dirz; float xn = (nextx + testposx - ffsx) * rdsx; float zn = (nextz + testposz - ffsz) * rdsz; // handles the following 2 case: // case1: (floor(to.x) == to.x) && (to.x < from.x) // In this case we calculate xn at to.x but set curx = to.x - 1, // and so we would be beyond the end of the ray. // case2: floating point precision issues if ((nextx - tsx) * dirx > 0) { xn=1337.0f; nextx=tsx; } if ((nextz - tsz) * dirz > 0) { zn=1337.0f; nextz=tsz; } // advance to the next nearest edge in either x or z dir, or in the case we reached the end make sure // we set it to the exact square positions (floating point precision sometimes hinders us to hit it) if (xn >= 1.0f && zn >= 1.0f) { assert(curx != nextx || curz != nextz); curx = nextx; curz = nextz; } else if (xn < zn) { assert(curx != nextx); curx = nextx; } else { assert(curz != nextz); curz = nextz; } } } return -1.0f; }
void AudioChannel::FindSourceAndPlay(size_t id, const float3& pos, const float3& velocity, float volume, bool relative) { boost::recursive_mutex::scoped_lock lck(soundMutex); if (!enabled) return; if (volume <= 0.0f) return; SoundItem* sndItem = sound->GetSoundItem(id); if (!sndItem) { sound->numEmptyPlayRequests++; return; } if (pos.distance(sound->GetListenerPos()) > sndItem->MaxDistance()) { if (!relative) { return; } else { LOG("CSound::PlaySample: maxdist ignored for relative playback: %s", sndItem->Name().c_str()); } } if (emmitsThisFrame >= emmitsPerFrame) return; emmitsThisFrame++; if (cur_sources.size() >= maxConcurrentSources) { CSoundSource* src = NULL; int prio = INT_MAX; for (std::map<CSoundSource*, bool>::iterator it = cur_sources.begin(); it != cur_sources.end(); ++it) { if (it->first->GetCurrentPriority() < prio) { src = it->first; prio = it->first->GetCurrentPriority(); } } if (src && prio <= sndItem->GetPriority()) { src->Stop(); } else { LOG_L(L_DEBUG, "CSound::PlaySample: Max concurrent sounds in channel reached! Dropping playback!"); return; } } CSoundSource* sndSource = sound->GetNextBestSource(); if (!sndSource) { LOG_L(L_DEBUG, "CSound::PlaySample: Max sounds reached! Dropping playback!"); return; } if (sndSource->GetCurrentPriority() < sndItem->GetPriority()) { if (sndSource->IsPlaying()) sound->numAbortedPlays++; sndSource->Play(this, sndItem, pos, velocity, volume, relative); CheckError("CSound::FindSourceAndPlay"); cur_sources[sndSource] = true; } }
float CAICallback::GetPathLength(float3 start, float3 end, int pathType, float goalRadius) { const int pathID = InitPath(start, end, pathType, goalRadius); float pathLen = -1.0f; if (pathID == 0) { return pathLen; } std::vector<float3> points; std::vector<int> lengths; pathManager->GetPathWayPoints(pathID, points, lengths); if (points.empty()) { return 0.0f; } // distance to first intermediate node pathLen = start.distance(points[0]); // we don't care which path segment has // what resolution, just lump all points // together for (size_t i = 1; i < points.size(); i++) { pathLen += points[i].distance(points[i - 1]); } /* // this method does not work without a path-owner // TODO: add an alternate GPL() callback for this? bool haveNextWP = true; float3 currWP = start; float3 nextWP = start; while (haveNextWP) { nextWP = GetNextWaypoint(pathID); if (nextWP.y == -2) { // next path node not yet known continue; } if (nextWP.y == -1) { if (nextWP.x >= 0.0f && nextWP.z >= 0.0f) { // end of path (nextWP == end) pathLen += (nextWP - currWP).Length2D(); } else { // invalid path pathLen = -1.0f; } haveNextWP = false; } else { pathLen += (nextWP - currWP).Length2D(); currWP = nextWP; } } */ FreePath(pathID); return pathLen; }