//* This only mostly works float Camera::getScreenRadius( const Sphere &sphere, float screenWidth, float screenHeight ) const { Vec2f screenCenter( worldToScreen( sphere.getCenter(), screenWidth, screenHeight ) ); Vec3f orthog = mViewDirection.getOrthogonal().normalized(); Vec2f screenPerimeter = worldToScreen( sphere.getCenter() + sphere.getRadius() * orthog, screenWidth, screenHeight ); return screenPerimeter.distance( screenCenter ); }
//* This only mostly works float Camera::getScreenRadius( const Sphere &sphere, float screenWidth, float screenHeight ) const { vec2 screenCenter( worldToScreen( sphere.getCenter(), screenWidth, screenHeight ) ); vec3 orthog = normalize( orthogonal( mViewDirection ) ); vec2 screenPerimeter = worldToScreen( sphere.getCenter() + sphere.getRadius() * orthog, screenWidth, screenHeight ); return distance( screenPerimeter, screenCenter ); }
void PowerUpGUIIcon::Render(const CU::Vector2<int>& aWindowSize, float aDeltaTime) { CU::Vector2<float> screenCenter(float(aWindowSize.x) * 0.5f, -float(aWindowSize.y) * 0.5f); if (myActive == true && myLastFrameActive == false) { myFadeUp = true; } if (myFadeUp == true) { myAlpha += 4 * aDeltaTime; if (myAlpha > 1.f) { myAlpha = 1.f; myFadeUp = false; } } if (myActive == true) { myActiveIcon->Render(screenCenter + myPosition, { myAlpha, myAlpha }, { 1.f, 1.f, 1.f, myAlpha }); if (myDuration != nullptr) { //rendertext på min pos Prism::Engine::GetInstance()->PrintText(*myDuration, screenCenter + myTextPosition, Prism::eTextType::RELEASE_TEXT); } } else { myInactiveIcon->Render(screenCenter + myPosition); } myLastFrameActive = myActive; }
void BGDialog::slotIdentifyScreens() { // Taken from PositionTab::showIdentify in kdebase/kcontrol/kicker/positiontab_impl.cpp for (unsigned s = 0; s < m_numScreens; s++) { QLabel *screenLabel = new QLabel(0, Qt::X11BypassWindowManagerHint); screenLabel->setObjectName("Screen Identify"); QFont identifyFont(KGlobalSettings::generalFont()); identifyFont.setPixelSize(100); screenLabel->setFont(identifyFont); screenLabel->setFrameStyle(QFrame::Panel); screenLabel->setFrameShadow(QFrame::Plain); screenLabel->setAlignment(Qt::AlignCenter); screenLabel->setNum(int(s + 1)); // BUGLET: we should not allow the identification to be entered again // until the timer fires. QTimer::singleShot(1500, screenLabel, SLOT(deleteLater())); QPoint screenCenter(QApplication::desktop()->screenGeometry(s).center()); QRect targetGeometry(QPoint(0, 0), screenLabel->sizeHint()); targetGeometry.moveCenter(screenCenter); screenLabel->setGeometry(targetGeometry); screenLabel->show(); } }
void Player::_handleOrientation() { Ogre::Vector2 cursor2DPos(_im->getMousePosX(), _im->getMousePosY()); Ogre::Vector2 screenCenter(_im->getMouseState().width / 2, _im->getMouseState().height / 2); Ogre::Vector2 playerToMouseVec = cursor2DPos - screenCenter; Ogre::Radian playerToMouseRad = Ogre::Math::ATan2(playerToMouseVec.x,playerToMouseVec.y); Ogre::Radian nullRad; gameObject->GetComponent<OgreObject::Mesh *>()->getNode()->resetOrientation(); gameObject->setRotation(nullRad, playerToMouseRad, nullRad); }
bool TurnController::endTurn(int i_status) { d_persons[d_turn].d_active &= ~i_status; std::vector<Magican*> vec = sideArray(d_persons[d_turn].d_side); if(d_persons[d_turn].d_active == 0 || !d_persons[d_turn].d_alive) { d_turn->setActive(false); d_turn = nullptr; } for( auto i : vec ) { d_persons[i].d_alive = i->isAlive(); if( d_persons[i].d_alive && d_persons[i].d_active>0 ) { return true; } } //change side do { if( ++d_iterSideTurn == d_sides.end() ) { ++d_turnNumber; d_iterSideTurn = d_sides.begin(); newTurn(); } } while(sideArray(*d_iterSideTurn).empty()); //make team active vec = sideArray(*d_iterSideTurn); for( auto i : vec ) { d_persons[i].d_active = TURN_MOVE | TURN_ATTACK; i->increaseMind(); //show message and centralize on first hero if( d_iterSideTurn == d_sides.begin() ) { MagicWars_NS::TouchControl::instance().centralizeOn((*sideArray(*d_iterSideTurn).begin())->getSprite()->getPosition()); cocos2d::Size visibleSize = cocos2d::Director::getInstance()->getVisibleSize(); cocos2d::Vec2 screenCenter(visibleSize.width/2, visibleSize.height/2); cocos2d::Director::getInstance()->getRunningScene()->addChild(UI_NS::Message::create(screenCenter, cocos2d::Color4F{0,0,0,0.5}, "Ваш ход")); } } return false; }
void TooltipPopup::showSlide() { if (isVisible() == false) { BaseLayer::inst()->showPopup(this, true, false); CCPoint p = ccp(getPositionX(), screenCenter().y+screenHeight()); setPosition(p); setOpacity(0); if (SceneManager::inst()->getCurSceneID() == kBattleScene) { runAction(CCSequence::createWithTwoActions(CCSpawn::createWithTwoActions(CCMoveTo::create(0.25, screenCenter()), CCFadeIn::create(0.25)), CCCallBlock::create([=]() { imcIES::GetMainThread()->PushStringID(getName().c_str()); imcIES::GetMainThread()->Run("POPUP_OPEN"); }) )); } else { runAction(CCSpawn::createWithTwoActions(CCMoveTo::create(0.25, screenCenter()), CCFadeIn::create(0.25))); } } }
void CBackgroundManager::centerTileMapOnTileCoord(Point tilePos) { // 获取屏幕大小和屏幕中心点 Size screenSize = Director::getInstance()->getWinSize(); Point screenCenter(screenSize.width * 0.5f, screenSize.height * 0.5f); // 仅在内部使用:瓷砖的Y坐标要减去1 tilePos.y -= 1; // 获取瓷砖坐标处以像素表示的坐标信息 Point scrollPosition = m_groundLayer->getPositionAt(tilePos); // 考虑到地图移动的情况,我将像素坐标信息乘以 -1,从而得到负值 scrollPosition = scrollPosition * -1; // 为屏幕中央坐标添加位移值 scrollPosition = scrollPosition + screenCenter; // 移动瓷砖地图 setPosition(scrollPosition * getScale()); // Action* move = [CCMoveTo actionWithDuration:0.2f position:scrollPosition]; // [tileMap stopAllActions]; // [tileMap runAction:move]; }
void CirclePainter::draw2D() { ofPushMatrix(); ofPushStyle(); ofPoint screenCenter(ofGetWindowWidth() / 2, ofGetWindowHeight() / 2); ofTranslate(screenCenter); ofFill(); ofSetColor(255, _tempo.getBeatProgress() * 255, _tempo.getBarProgress() * 255); ofCircle(ofPoint(), _radius.value); ofSetColor(255, 0, 0); _fill ? ofFill() : ofNoFill(); ofPoint xy = ofPoint(cosf(_theta), sinf(_theta)); ofPoint orbital = xy *_radius.value; ofCircle(orbital, _radius.value / 10); ofPopStyle(); ofPopMatrix(); }
bool TooltipPopup::initWithFile(const char * filename) { if (Button::initWithFile(filename) == false) { return false; } m_scaleWhenTouch = false; setVisible(false); m_icon = NULL; m_nameLabel = CCLabelTTF::create(); m_nameLabel->setFontSize(size(28)); m_nameLabel->setAnchorPoint(ccp(0.5, 1)); m_nameLabel->setPosition(ccp(getContentSize().width/2, getContentSize().height-size(12))); CCSprite::addChild(m_nameLabel); m_descLabel = CCLabelTTF::create(); m_descLabel->setDimensions(sizeRect(290, 230)); m_descLabel->setFontSize(size(20)); m_descLabel->setAnchorPoint(ccp(0,1)); m_descLabel->setPosition(posLocalLT(this, 105, 60)); CCSprite::addChild(m_descLabel); m_subDescLabel = CCLabelTTF::create(); m_subDescLabel->setAnchorPoint(ccp(0,1)); m_subDescLabel->setFontSize(size(20)); CCSprite::addChild(m_subDescLabel); setPosition(screenCenter()); setVisible(false); BaseLayer::inst()->addButton(this); BaseLayer::inst()->addChild(this, z_popup_ui); return true; }
void IngameState::tick(float dt) { autolookTimer = std::max(autolookTimer - dt, 0.f); auto player = game->getPlayer(); if( player && player->isInputEnabled() ) { sf::Vector2f screenSize(getWindow().getSize()); sf::Vector2f screenCenter(screenSize / 2.f); sf::Vector2f mouseMove; if (game->hasFocus()) { sf::Vector2f mousePos(sf::Mouse::getPosition(getWindow())); sf::Vector2f deltaMouse = (mousePos - screenCenter); mouseMove = sf::Vector2f(deltaMouse.x / screenSize.x, deltaMouse.y / screenSize.y); sf::Mouse::setPosition(sf::Vector2i(screenCenter), getWindow()); if(deltaMouse.x != 0 || deltaMouse.y != 0) { autolookTimer = kAutoLookTime; if (!m_invertedY) { mouseMove.y = -mouseMove.y; } m_cameraAngles += glm::vec2(mouseMove.x, mouseMove.y); m_cameraAngles.y = glm::clamp(m_cameraAngles.y, kCameraPitchLimit, glm::pi<float>() - kCameraPitchLimit); } } float viewDistance = 4.f; switch( camMode ) { case IngameState::CAMERA_CLOSE: viewDistance = 2.f; break; case IngameState::CAMERA_NORMAL: viewDistance = 4.0f; break; case IngameState::CAMERA_FAR: viewDistance = 6.f; break; case IngameState::CAMERA_TOPDOWN: viewDistance = 15.f; break; default: viewDistance = 4.f; } auto target = getWorld()->pedestrianPool.find(getWorld()->state->cameraTarget); if( target == nullptr ) { target = player->getCharacter(); } glm::vec3 targetPosition = target->getPosition(); glm::vec3 lookTargetPosition = targetPosition; targetPosition += glm::vec3(0.f, 0.f, 1.f); lookTargetPosition += glm::vec3(0.f, 0.f, 0.5f); btCollisionObject* physTarget = player->getCharacter()->physObject; auto vehicle = ( target->type() == GameObject::Character ) ? static_cast<CharacterObject*>(target)->getCurrentVehicle() : nullptr; if( vehicle ) { auto model = vehicle->model; float maxDist = 0.f; for(auto& g : model->resource->geometries) { float partSize = glm::length(g->geometryBounds.center) + g->geometryBounds.radius; maxDist = std::max(partSize, maxDist); } viewDistance = viewDistance + maxDist; targetPosition = vehicle->getPosition(); lookTargetPosition = targetPosition; lookTargetPosition.z += (vehicle->info->handling.dimensions.z); targetPosition.z += (vehicle->info->handling.dimensions.z * 1.f); physTarget = vehicle->physBody; if (!m_vehicleFreeLook) { m_cameraAngles.y = kVehicleCameraPitch; } // Rotate the camera to the ideal angle if the player isn't moving it float velocity = vehicle->getVelocity(); if (autolookTimer <= 0.f && glm::abs(velocity) > kAutolookMinVelocity) { auto idealYaw = -glm::roll(vehicle->getRotation()) + glm::half_pi<float>(); const auto idealPitch = kVehicleCameraPitch; if (velocity < 0.f) { idealYaw = glm::mod(idealYaw - glm::pi<float>(), glm::pi<float>() * 2.f); } float currentYaw = glm::mod(m_cameraAngles.x, glm::pi<float>()*2); float currentPitch = m_cameraAngles.y; float deltaYaw = idealYaw - currentYaw; float deltaPitch = idealPitch - currentPitch; if (glm::abs(deltaYaw) > glm::pi<float>()) { deltaYaw -= glm::sign(deltaYaw) * glm::pi<float>()*2.f; } m_cameraAngles.x += glm::sign(deltaYaw) * std::min(kMaxRotationRate * dt, glm::abs(deltaYaw)); m_cameraAngles.y += glm::sign(deltaPitch) * std::min(kMaxRotationRate * dt, glm::abs(deltaPitch)); } } // Non-topdown camera can orbit if( camMode != IngameState::CAMERA_TOPDOWN ) { // Determine the "ideal" camera position for the current view angles auto yaw = glm::angleAxis(m_cameraAngles.x, glm::vec3(0.f, 0.f,-1.f)); auto pitch = glm::angleAxis(m_cameraAngles.y, glm::vec3(0.f, 1.f, 0.f)); auto cameraOffset = yaw * pitch * glm::vec3(0.f, 0.f, viewDistance); cameraPosition = targetPosition + cameraOffset; } else { cameraPosition = targetPosition + glm::vec3(0.f, 0.f, viewDistance); } glm::quat angle; auto camtotarget = targetPosition - cameraPosition; auto dir = glm::normalize(camtotarget); float correction = glm::length(camtotarget) - viewDistance; if( correction < 0.f ) { float innerDist = viewDistance * 0.1f; correction = glm::min(0.f, correction + innerDist); } cameraPosition += dir * 10.f * correction * dt; auto lookdir = glm::normalize(lookTargetPosition - cameraPosition); // Calculate the yaw to look at the target. float angleYaw = glm::atan(lookdir.y, lookdir.x); angle = glm::quat( glm::vec3(0.f, 0.f, angleYaw) ); // Update player with camera yaw if( player->isInputEnabled() ) { if (player->getCharacter()->getCurrentVehicle()) { player->setMoveDirection(_movement); } else { float length = glm::length(_movement); float movementAngle = angleYaw - M_PI/2.f; if (length > 0.1f) { glm::vec3 direction = glm::normalize(_movement); movementAngle += atan2(direction.y, direction.x); player->setMoveDirection(glm::vec3(1.f, 0.f, 0.f)); } else { player->setMoveDirection(glm::vec3(0.f)); } if (player->getCharacter()->canTurn()) { player->getCharacter()->rotation = glm::angleAxis(movementAngle, glm::vec3(0.f, 0.f, 1.f)); } } } else { player->setMoveDirection(glm::vec3(0.f)); } float len2d = glm::length(glm::vec2(lookdir)); float anglePitch = glm::atan(lookdir.z, len2d); angle *= glm::quat( glm::vec3(0.f, -anglePitch, 0.f) ); // Use rays to ensure target is visible from cameraPosition auto rayEnd = cameraPosition; auto rayStart = targetPosition; auto to = btVector3(rayEnd.x, rayEnd.y, rayEnd.z); auto from = btVector3(rayStart.x, rayStart.y, rayStart.z); ClosestNotMeRayResultCallback ray(physTarget, from, to); getWorld()->dynamicsWorld->rayTest(from, to, ray); if( ray.hasHit() && ray.m_closestHitFraction < 1.f ) { cameraPosition = glm::vec3(ray.m_hitPointWorld.x(), ray.m_hitPointWorld.y(), ray.m_hitPointWorld.z()); cameraPosition += glm::vec3(ray.m_hitNormalWorld.x(), ray.m_hitNormalWorld.y(), ray.m_hitNormalWorld.z()) * 0.1f; } _look.position = cameraPosition; _look.rotation = angle; } }
vector<TrialData_t> generateTrials (int trialCount) { vector<ofColor> objectColors; vector<ofPoint> objectLocations; //Set up a vector of colors that will be sampled to make the objects. objectColors.push_back(ofColor::red); objectColors.push_back(ofColor::orange); objectColors.push_back(ofColor::yellow); objectColors.push_back(ofColor::green); objectColors.push_back(ofColor::blue); objectColors.push_back(ofColor::purple); //Make a 3x3 grid of object locations around the center of the screen. ofPoint screenCenter(Disp.getResolution().x / 2, Disp.getResolution().y / 2); for (int i = 0; i < 9; i++) { int col = i % 3; int row = i / 3; ofPoint p; p.x = screenCenter.x - 100 + (row * 100); p.y = screenCenter.y - 100 + (col * 100); objectLocations.push_back(p); } vector<bool> changeTrial = RNG.sample(trialCount, Util::concatenate<bool>(false, true), true); vector<TrialData_t> _trials; for (int trial = 0; trial < trialCount; trial++) { TrialData_t tr; tr.arraySize = 4; //This randomly picks tr.arraySize colors from objectColors without replacement. //RNG is the global Random Number Generator object that is useful for a wide variety of randomization stuff. tr.colors = RNG.sample(tr.arraySize, objectColors, false); tr.locations = RNG.sample(tr.arraySize, objectLocations, false); tr.changeTrial = changeTrial[trial]; if (tr.changeTrial) { //If something is going to change, we have to pick which object will change. //RNG.randomInt() returns an unsigned int from the given range (including both endpoints). tr.changedObjectIndex = RNG.randomInt(0, tr.arraySize - 1); //For the new color, sample 1 color from objectColors, excluding any of //the colors already selected for the trial (the 1 is implicit). tr.newColor = RNG.sampleExclusive(objectColors, tr.colors); } else { //You don't have to set the newColor or the changedObjectIndex for a no-change trial because there is no change and they won't be used. tr.changedObjectIndex = -1; //But we'll set them anyway to unreasonable values just to make sure they aren't mistaken for real values. tr.newColor = backgroundColor; } _trials.push_back( tr ); } //This version of shuffleVector() (which takes the address of a vector) shuffles the argument, returning nothing. RNG.shuffleVector( &_trials ); return _trials; }
void DefenderWeaponBehaviour::dealDamage(ComponentWrapper cWeapon, WeaponInfo& wi, const std::vector<glm::vec2>& pattern) { // Only deal damage client side if (!IsClient) { return; } // Only handle shooting for the local player if (wi.Player != LocalPlayer) { return; } // Make sure the player isn't shooting from the grave if (!wi.Player.Valid()) { return; } // Convert the spread angle to screen coordinates, taking FOV into account Rectangle res = m_Renderer->GetViewportSize(); float spreadAngle = glm::radians((float)cWeapon["SpreadAngle"]); float nearClip = (double)m_CurrentCamera["Camera"]["NearClip"]; float farClip = (double)m_CurrentCamera["Camera"]["FarClip"]; float yFOV = glm::radians((double)m_CurrentCamera["Camera"]["FOV"]); //float yRefFOV = glm::radians(59.f); //float yRef = glm::tan(yRefFOV) * nearClip; //float yRatio = yRef / (glm::tan(yFOV) * nearClip); //float yMax = (yRatio / 2.f) * spreadAngle * (res.Height / 2.f); float yRefFOV = glm::radians(59.f); float yRef = glm::tan(yRefFOV) * nearClip; float yRatio = yRef / (glm::tan(yFOV) * nearClip); float yMax = yRatio * (glm::tan(spreadAngle) * (farClip - nearClip)) * glm::pi<float>(); // ????? Good enough???? LOG_DEBUG("Ratio: %f", yRatio); LOG_DEBUG("fatClip: %f", farClip); LOG_DEBUG("yMax: %f", yMax); double pelletDamage = (double)cWeapon["BaseDamage"] / pattern.size(); // Pick! std::unordered_map<EntityWrapper, double> damageSum; glm::vec2 screenCenter(res.Width / 2.f, res.Height / 2.f); for (auto& pellet : pattern) { glm::vec2 pickCoord = screenCenter + (pellet * glm::vec2(yMax, yMax)); PickData pick = m_Renderer->Pick(pickCoord); EntityWrapper victim(m_World, pick.Entity); if (!victim.Valid()) { continue; } // Temp hit decal // EntityWrapper hit = ResourceManager::Load<EntityFile>("Schema/Entities/HitTest.xml")->MergeInto(m_World); // (Field<glm::vec3>)hit["Transform"]["Position"] = pick.Position; // Don't let us shoot ourselves in the foot somehow if (victim == LocalPlayer) { continue; } // Only care about players being hit if (!victim.HasComponent("Player")) { victim = victim.FirstParentWithComponent("Player"); if (!victim.Valid()) { continue; } } // Check for friendly fire if ((ComponentInfo::EnumType)victim["Team"]["Team"] == (ComponentInfo::EnumType)wi.Player["Team"]["Team"]) { // Give boost Events::PlayerDamage ePlayerDamage; ePlayerDamage.Inflictor = wi.Player; ePlayerDamage.Victim = victim; ePlayerDamage.Damage = 0; m_EventBroker->Publish(ePlayerDamage); continue; } damageSum[victim] += pelletDamage; // ((Field<glm::vec4>)hit["Model"]["Color"]).z(1.f); } // Deal damage! for (auto& kv : damageSum) { // Deal damage! Events::PlayerDamage ePlayerDamage; ePlayerDamage.Inflictor = wi.Player; ePlayerDamage.Victim = kv.first; ePlayerDamage.Damage = kv.second; m_EventBroker->Publish(ePlayerDamage); } }
void LightFlareData::prepRender( SceneState *state, LightFlareState *flareState ) { PROFILE_SCOPE( LightFlareData_prepRender ); // No elements then nothing to render. if ( mElementCount == 0 ) return; // We need these all over the place later. const Point3F &camPos = state->getCameraPosition(); const RectI &viewport = GFX->getViewport(); const Point3F &lightPos = flareState->lightMat.getPosition(); LightInfo *lightInfo = flareState->lightInfo; bool isVectorLight = lightInfo->getType() == LightInfo::Vector; // Perform visibility testing on the light... // Project the light position from world to screen space, we need this // position later, and it tells us if it is actually onscreen. Point3F lightPosSS; bool onscreen = MathUtils::mProjectWorldToScreen( lightPos, &lightPosSS, viewport, GFX->getWorldMatrix(), gClientSceneGraph->getNonClipProjection() ); U32 visDelta = U32_MAX; U32 fadeOutTime = 20; U32 fadeInTime = 125; // Fade factor based on amount of occlusion. F32 occlusionFade = 1.0f; bool lightVisible = true; if ( !state->isReflectPass() ) { // It is onscreen, so raycast as a simple occlusion test. U32 losMask = STATIC_COLLISION_MASK | ShapeBaseObjectType | StaticTSObjectType | ItemObjectType | PlayerObjectType; GameConnection *conn = GameConnection::getConnectionToServer(); if ( !conn ) return; bool needsRaycast = true; // NOTE: if hardware does not support HOQ it will return NULL // and we will retry every time but there is not currently a good place // for one-shot initialization of LightFlareState if ( flareState->occlusionQuery == NULL ) flareState->occlusionQuery = GFX->createOcclusionQuery(); if ( flareState->fullPixelQuery == NULL ) flareState->fullPixelQuery = GFX->createOcclusionQuery(); if ( flareState->occlusionQuery && ( ( isVectorLight && flareState->worldRadius > 0.0f ) || ( !isVectorLight && mOcclusionRadius > 0.0f ) ) ) { // Always treat light as onscreen if using HOQ // it will be faded out if offscreen anyway. onscreen = true; U32 pixels = -1; GFXOcclusionQuery::OcclusionQueryStatus status = flareState->occlusionQuery->getStatus( true, &pixels ); String str = flareState->occlusionQuery->statusToString( status ); Con::setVariable( "$Flare::OcclusionStatus", str.c_str() ); Con::setIntVariable( "$Flare::OcclusionVal", pixels ); if ( status == GFXOcclusionQuery::Occluded ) occlusionFade = 0.0f; if ( status != GFXOcclusionQuery::Unset ) needsRaycast = false; RenderPassManager *pass = state->getRenderPass(); OccluderRenderInst *ri = pass->allocInst<OccluderRenderInst>(); Point3F scale( Point3F::One ); if ( isVectorLight && flareState->worldRadius > 0.0f ) scale *= flareState->worldRadius; else scale *= mOcclusionRadius; ri->type = RenderPassManager::RIT_Occluder; ri->query = flareState->occlusionQuery; ri->query2 = flareState->fullPixelQuery; ri->position = lightPos; ri->scale = scale; ri->orientation = pass->allocUniqueXform( lightInfo->getTransform() ); ri->isSphere = true; state->getRenderPass()->addInst( ri ); if ( status == GFXOcclusionQuery::NotOccluded ) { U32 fullPixels; flareState->fullPixelQuery->getStatus( true, &fullPixels ); occlusionFade = (F32)pixels / (F32)fullPixels; // Approximation of the full pixel count rather than doing // two queries, but it is not very accurate. /* F32 dist = ( camPos - lightPos ).len(); F32 radius = scale.x; radius = ( radius / dist ) * state->getWorldToScreenScale().y; occlusionFade = (F32)pixels / (4.0f * radius * radius); occlusionFade = mClampF( occlusionFade, 0.0f, 1.0f ); */ } } Con::setFloatVariable( "$Flare::OcclusionFade", occlusionFade ); if ( needsRaycast ) { // Use a raycast to determine occlusion. bool fps = conn->isFirstPerson(); GameBase *control = conn->getControlObject(); if ( control && fps ) control->disableCollision(); RayInfo rayInfo; if ( gClientContainer.castRayRendered( camPos, lightPos, losMask, &rayInfo ) ) occlusionFade = 0.0f; if ( control && fps ) control->enableCollision(); } lightVisible = onscreen && occlusionFade > 0.0f; // To perform a fade in/out when we gain or lose visibility // we must update/store the visibility state and time. U32 currentTime = Sim::getCurrentTime(); if ( lightVisible != flareState->visible ) { flareState->visible = lightVisible; flareState->visChangedTime = currentTime; } // Save this in the state so that we have it during the reflect pass. flareState->occlusion = occlusionFade; visDelta = currentTime - flareState->visChangedTime; } else // state->isReflectPass() { occlusionFade = flareState->occlusion; lightVisible = flareState->visible; visDelta = Sim::getCurrentTime() - flareState->visChangedTime; } // We can only skip rendering if the light is not visible, and it // has elapsed the fadeOutTime. if ( !lightVisible && visDelta > fadeOutTime ) return; // In a reflection we only render the elements with zero distance. U32 elementCount = mElementCount; if ( state->isReflectPass() ) { elementCount = 0; for ( ; elementCount < mElementCount; elementCount++ ) { if ( mElementDist[elementCount] > 0.0f ) break; } } if ( elementCount == 0 ) return; // A bunch of preparatory math before generating verts... const Point2I &vpExtent = viewport.extent; Point3F viewportExtent( vpExtent.x, vpExtent.y, 1.0f ); Point2I halfViewportExtentI( viewport.extent / 2 ); Point3F halfViewportExtentF( (F32)halfViewportExtentI.x * 0.5f, (F32)halfViewportExtentI.y, 0.0f ); Point3F screenCenter( 0,0,0 ); Point3F oneOverViewportExtent( 1.0f / viewportExtent.x, 1.0f / viewportExtent.y, 1.0f ); lightPosSS.y -= viewport.point.y; lightPosSS *= oneOverViewportExtent; lightPosSS = ( lightPosSS * 2.0f ) - Point3F::One; lightPosSS.y = -lightPosSS.y; lightPosSS.z = 0.0f; Point3F flareVec( screenCenter - lightPosSS ); F32 flareLength = flareVec.len(); flareVec.normalizeSafe(); Point3F basePoints[4]; basePoints[0] = Point3F( -0.5, 0.5, 0.0 ); basePoints[1] = Point3F( -0.5, -0.5, 0.0 ); basePoints[2] = Point3F( 0.5, -0.5, 0.0 ); basePoints[3] = Point3F( 0.5, 0.5, 0.0 ); Point3F rotatedBasePoints[4]; rotatedBasePoints[0] = basePoints[0]; rotatedBasePoints[1] = basePoints[1]; rotatedBasePoints[2] = basePoints[2]; rotatedBasePoints[3] = basePoints[3]; Point3F fvec( -1, 0, 0 ); F32 rot = mAcos( mDot( fvec, flareVec ) ); Point3F rvec( 0, -1, 0 ); rot *= mDot( rvec, flareVec ) > 0.0f ? 1.0f : -1.0f; vectorRotateZAxis( rotatedBasePoints[0], rot ); vectorRotateZAxis( rotatedBasePoints[1], rot ); vectorRotateZAxis( rotatedBasePoints[2], rot ); vectorRotateZAxis( rotatedBasePoints[3], rot ); // Here we calculate a the light source's influence on the effect's size // and brightness... // Scale based on the current light brightness compared to its normal output. F32 lightSourceBrightnessScale = lightInfo->getBrightness() / flareState->fullBrightness; // Scale based on world space distance from camera to light source. F32 lightSourceWSDistanceScale = ( isVectorLight ) ? 1.0f : getMin( 10.0f / ( lightPos - camPos ).len(), 1.5f ); // Scale based on screen space distance from screen position of light source to the screen center. F32 lightSourceSSDistanceScale = ( 1.5f - ( lightPosSS - screenCenter ).len() ) / 1.5f; // Scale based on recent visibility changes, fading in or out. F32 fadeInOutScale = 1.0f; if ( lightVisible && visDelta < fadeInTime && flareState->occlusion ) fadeInOutScale = (F32)visDelta / (F32)fadeInTime; else if ( !lightVisible && visDelta < fadeOutTime ) fadeInOutScale = 1.0f - (F32)visDelta / (F32)fadeOutTime; // This combined scale influences the size of all elements this effect renders. // Note we also add in a scale that is user specified in the Light. F32 lightSourceIntensityScale = lightSourceBrightnessScale * lightSourceWSDistanceScale * lightSourceSSDistanceScale * fadeInOutScale * flareState->scale * occlusionFade; // The baseColor which modulates the color of all elements. ColorF baseColor; if ( flareState->fullBrightness == 0.0f ) baseColor = ColorF::BLACK; else // These are the factors which affect the "alpha" of the flare effect. // Modulate more in as appropriate. baseColor = ColorF::WHITE * lightSourceBrightnessScale * occlusionFade; // Fill in the vertex buffer... const U32 vertCount = 4 * elementCount; if ( flareState->vertBuffer.isNull() || flareState->vertBuffer->mNumVerts != vertCount ) flareState->vertBuffer.set( GFX, vertCount, GFXBufferTypeDynamic ); GFXVertexPCT *pVert = flareState->vertBuffer.lock(); const Point2I &widthHeightI = mFlareTexture.getWidthHeight(); Point2F oneOverTexSize( 1.0f / (F32)widthHeightI.x, 1.0f / (F32)widthHeightI.y ); for ( U32 i = 0; i < elementCount; i++ ) { Point3F *basePos = mElementRotate[i] ? rotatedBasePoints : basePoints; ColorF elementColor( baseColor * mElementTint[i] ); if ( mElementUseLightColor[i] ) elementColor *= lightInfo->getColor(); Point3F elementPos; elementPos = lightPosSS + flareVec * mElementDist[i] * flareLength; elementPos.z = 0.0f; F32 maxDist = 1.5f; F32 elementDist = mSqrt( ( elementPos.x * elementPos.x ) + ( elementPos.y * elementPos.y ) ); F32 distanceScale = ( maxDist - elementDist ) / maxDist; distanceScale = 1.0f; const RectF &elementRect = mElementRect[i]; Point3F elementSize( elementRect.extent.x, elementRect.extent.y, 1.0f ); elementSize *= mElementScale[i] * distanceScale * mScale * lightSourceIntensityScale; if ( elementSize.x < 100.0f ) { F32 alphaScale = mPow( elementSize.x / 100.0f, 2 ); elementColor *= alphaScale; } elementColor.clamp(); Point2F texCoordMin, texCoordMax; texCoordMin = elementRect.point * oneOverTexSize; texCoordMax = ( elementRect.point + elementRect.extent ) * oneOverTexSize; pVert->color = elementColor; pVert->point = ( basePos[0] * elementSize * oneOverViewportExtent ) + elementPos; pVert->texCoord.set( texCoordMin.x, texCoordMax.y ); pVert++; pVert->color = elementColor; pVert->point = ( basePos[1] * elementSize * oneOverViewportExtent ) + elementPos; pVert->texCoord.set( texCoordMax.x, texCoordMax.y ); pVert++; pVert->color = elementColor; pVert->point = ( basePos[2] * elementSize * oneOverViewportExtent ) + elementPos; pVert->texCoord.set( texCoordMax.x, texCoordMin.y ); pVert++; pVert->color = elementColor; pVert->point = ( basePos[3] * elementSize * oneOverViewportExtent ) + elementPos; pVert->texCoord.set( texCoordMin.x, texCoordMin.y ); pVert++; } flareState->vertBuffer.unlock(); // Create and submit the render instance... RenderPassManager *renderManager = state->getRenderPass(); ParticleRenderInst *ri = renderManager->allocInst<ParticleRenderInst>(); ri->vertBuff = &flareState->vertBuffer; ri->primBuff = &mFlarePrimBuffer; ri->translucentSort = true; ri->type = RenderPassManager::RIT_Particle; ri->sortDistSq = ( lightPos - camPos ).lenSquared(); ri->modelViewProj = &MatrixF::Identity; ri->bbModelViewProj = ri->modelViewProj; ri->count = elementCount; // Only draw the light flare in high-res mode, never off-screen mode ri->systemState = ParticleRenderInst::AwaitingHighResDraw; ri->blendStyle = ParticleRenderInst::BlendGreyscale; ri->diffuseTex = &*(mFlareTexture); ri->softnessDistance = 1.0f; // Sort by texture too. ri->defaultKey = ri->diffuseTex ? (U32)ri->diffuseTex : (U32)ri->vertBuff; renderManager->addInst( ri ); }