void TimeOfDay::_updatePosition() { //// Full azimuth/elevation calculation. //// calculate sun decline and meridian angle (in radians) //F32 sunDecline = mSin( M_2PI * mTimeOfYear ) * mDegToRad( mAxisTilt ); //F32 meridianAngle = mTimeOfDay * M_2PI - mDegToRad( mLongitude ); //// calculate the elevation and azimuth (in radians) //mElevation = _calcElevation( mDegToRad( mLatitude ), sunDecline, meridianAngle ); //mAzimuth = _calcAzimuth( mDegToRad( mLatitude ), sunDecline, meridianAngle ); // Simplified azimuth/elevation calculation. // calculate sun decline and meridian angle (in radians) F32 sunDecline = mDegToRad( mAxisTilt ); F32 meridianAngle = mTimeOfDay * M_2PI; mPrevElevation = mNextElevation; // calculate the elevation and azimuth (in radians) mElevation = _calcElevation( 0.0f, sunDecline, meridianAngle ); mAzimuth = _calcAzimuth( 0.0f, sunDecline, meridianAngle ); if ( mFabs( mAzimuthOverride ) ) { mElevation = mDegToRad( mTimeOfDay * 360.0f ); mAzimuth = mAzimuthOverride; } mNextElevation = mElevation; // Only the client updates the sun position! if ( isClientObject() ) smTimeOfDayUpdateSignal.trigger( this, mTimeOfDay ); }
void SFXXAudioVoice::setCone( F32 innerAngle, F32 outerAngle, F32 outerVolume ) { // If the cone is set to 360 then the // cone is null and doesn't need to be // set on the voice. if ( mIsEqual( innerAngle, 360 ) ) { SAFE_DELETE( mEmitter.pCone ); return; } if ( !mEmitter.pCone ) { mEmitter.pCone = new X3DAUDIO_CONE; // The inner volume is always 1... the overall // volume is what scales it. mEmitter.pCone->InnerVolume = 1.0f; // We don't use these yet. mEmitter.pCone->InnerLPF = 0.0f; mEmitter.pCone->OuterLPF = 0.0f; mEmitter.pCone->InnerReverb = 0.0f; mEmitter.pCone->OuterReverb = 0.0f; } mEmitter.pCone->InnerAngle = mDegToRad( innerAngle ); mEmitter.pCone->OuterAngle = mDegToRad( outerAngle ); mEmitter.pCone->OuterVolume = outerVolume; }
void LightAnimData::animate( LightInfo *lightInfo, LightAnimState *state ) { PROFILE_SCOPE( LightAnimData_animate ); // Calculate the input time for animation. F32 time = state->animationPhase + ( (F32)Sim::getCurrentTime() * 0.001f ) / state->animationPeriod; MatrixF transform( state->transform ); EulerF euler( Point3F::Zero ); if ( mRot.animate( time, euler ) ) { euler.x = mDegToRad( euler.x ); euler.y = mDegToRad( euler.y ); euler.z = mDegToRad( euler.z ); MatrixF rot( euler ); transform.mul( rot ); } Point3F offset( Point3F::Zero ); if ( mOffset.animate( time, offset ) ) transform.displace( offset ); lightInfo->setTransform( transform ); ColorF color = state->color; mColor.animate( time, color ); lightInfo->setColor( color ); F32 brightness = state->brightness; mBrightness.animate( time, &brightness ); lightInfo->setBrightness( brightness ); }
// GuiMaterialPreview GuiMaterialPreview::GuiMaterialPreview() : mMouseState(None), mModel(NULL), runThread(0), lastRenderTime(0), mLastMousePoint(0, 0), mFakeSun(NULL), mMaxOrbitDist(5.0f), mMinOrbitDist(0.0f), mOrbitDist(5.0f) { mActive = true; mCameraMatrix.identity(); mCameraRot.set( mDegToRad(30.0f), 0, mDegToRad(-30.0f) ); mCameraPos.set(0.0f, 1.75f, 1.25f); mCameraMatrix.setColumn(3, mCameraPos); mOrbitPos.set(0.0f, 0.0f, 0.0f); mTransStep = 0.01f; mTranMult = 4.0; mLightTransStep = 0.01f; mLightTranMult = 4.0; mOrbitRelPos = Point3F(0,0,0); // By default don't do dynamic reflection // updates for this viewport. mReflectPriority = 0.0f; }
void afxZodiacData::convertGradientRangeFromDegrees(Point2F& gradrange, const Point2F& gradrange_deg) { F32 x = mCos(mDegToRad(gradrange_deg.x)); F32 y = mCos(mDegToRad(gradrange_deg.y)); if (y > x) gradrange.set(x, y); else gradrange.set(y, x); }
// This function is meant to be used with a button to put everything back to default settings. void GuiMaterialPreview::resetViewport() { // Reset the camera's orientation. mCameraRot.set( mDegToRad(30.0f), 0, mDegToRad(-30.0f) ); mCameraPos.set(0.0f, 1.75f, 1.25f); mOrbitDist = 5.0f; mOrbitPos = mModel->getShape()->center; // Reset the viewport's lighting. GuiMaterialPreview::mFakeSun->setColor( ColorF( 1.0f, 1.0f, 1.0f ) ); GuiMaterialPreview::mFakeSun->setAmbient( ColorF( 0.5f, 0.5f, 0.5f ) ); GuiMaterialPreview::mFakeSun->setDirection( VectorF( 0.0f, 0.707f, -0.707f ) ); }
void PaintMaterialAction::process(Selection * sel, const Gui3DMouseEvent &, bool selChanged, Type) { S32 mat = mTerrainEditor->getPaintMaterialIndex(); if ( !selChanged || mat < 0 ) return; const bool slopeLimit = mTerrainEditor->mSlopeMinAngle > 0.0f || mTerrainEditor->mSlopeMaxAngle < 90.0f; const F32 minSlope = mSin( mDegToRad( 90.0f - mTerrainEditor->mSlopeMinAngle ) ); const F32 maxSlope = mSin( mDegToRad( 90.0f - mTerrainEditor->mSlopeMaxAngle ) ); const TerrainBlock *terrain = mTerrainEditor->getActiveTerrain(); const F32 squareSize = terrain->getSquareSize(); Point2F p; Point3F norm; for( U32 i = 0; i < sel->size(); i++ ) { GridInfo &inf = (*sel)[i]; if ( slopeLimit ) { p.x = inf.mGridPoint.gridPos.x * squareSize; p.y = inf.mGridPoint.gridPos.y * squareSize; if ( !terrain->getNormal( p, &norm, true ) ) continue; if ( norm.z > minSlope || norm.z < maxSlope ) continue; } // If grid is already set to our material, or it is an // empty grid spot, then skip painting. if ( inf.mMaterial == mat || inf.mMaterial == U8_MAX ) continue; if ( mRandF() > mTerrainEditor->getBrushPressure() ) continue; inf.mMaterialChanged = true; mTerrainEditor->getUndoSel()->add(inf); // Painting is really simple now... set the one mat index. inf.mMaterial = mat; mTerrainEditor->setGridInfo(inf, true); } mTerrainEditor->scheduleMaterialUpdate(); }
bool AITurretShape::onNewDataBlock(GameBaseData* dptr, bool reload) { mDataBlock = dynamic_cast<AITurretShapeData*>(dptr); if (!mDataBlock || !Parent::onNewDataBlock(dptr, reload)) return false; mScanHeading = mDegToRad(mDataBlock->maxScanHeading); if (mIsZero(mScanHeading)) mScanHeading = M_PI_F; mScanPitch = mDegToRad(mDataBlock->maxScanPitch); if (mIsZero(mScanPitch)) mScanPitch = M_PI_F; mScanDistance = mDataBlock->maxScanDistance; mScanDistanceSquared = mScanDistance * mScanDistance; mWeaponRangeSquared = mDataBlock->maxWeaponRange * mDataBlock->maxWeaponRange; mWeaponLeadVelocitySquared = (mDataBlock->weaponLeadVelocity > 0) ? (mDataBlock->weaponLeadVelocity * mDataBlock->weaponLeadVelocity) : 0; // The scan box is built such that the scanning origin is at (0,0,0) and the scanning distance // is out along the y axis. When this is transformed to the turret's location is provides a // scanning volume in front of the turret. F32 scanX = mScanDistance*mSin(mScanHeading); F32 scanY = mScanDistance; F32 scanZ = mScanDistance*mSin(mScanPitch); mScanBox.set(-scanX, 0, -scanZ, scanX, scanY, scanZ); mScanTickFrequency = mDataBlock->scanTickFrequency; if (mScanTickFrequency < 1) mScanTickFrequency = 1; mScanTickFrequencyVariance = mDataBlock->scanTickFrequencyVariance; if (mScanTickFrequencyVariance < 0) mScanTickFrequencyVariance = 0; mTicksToNextScan = mScanTickFrequency; // For states mStateAnimThread = 0; if (mDataBlock->isAnimated) { mStateAnimThread = mShapeInstance->addThread(); mShapeInstance->setTimeScale(mStateAnimThread,0); } scriptOnNewDataBlock(); return true; }
virtual void interpolate(F32 t, afxXM_Params& params) { F32 theta = mDegToRad(lerp(t, a, b)); AngAxisF rot_aa(axis, theta); MatrixF rot_xfm; rot_aa.setMatrix(&rot_xfm); params.ori.mul(rot_xfm); }
void GFXDrawUtil::drawArrow( const GFXStateBlockDesc &desc, const Point3F &start, const Point3F &end, const ColorI &color ) { GFXTransformSaver saver; // Direction and length of the arrow. VectorF dir = end - start; F32 len = dir.len(); dir.normalize(); len *= 0.2f; // Base of the cone will be a distance back from the end of the arrow // proportional to the total distance of the arrow... 0.3f looks about right. Point3F coneBase = end - dir * len * 0.3f; // Calculate the radius of the cone given that we want the cone to have // an angle of 25 degrees (just because it looks good). F32 coneLen = ( end - coneBase ).len(); F32 coneDiameter = mTan( mDegToRad(25.0f) ) * coneLen; // Draw the cone on at the arrow's tip. drawCone( desc, coneBase, end, coneDiameter / 2.0f, color ); // Get the difference in length from // the start of the cone to the end // of the cylinder so we can put the // end of the cylinder right against where // the cone starts. Point3F coneDiff = end - coneBase; // Draw the cylinder. F32 stickRadius = len * 0.025f; drawCylinder( desc, start, end - coneDiff, stickRadius, color ); }
TurretShape::TurretShape() { mTypeMask |= VehicleObjectType | DynamicShapeObjectType; mDataBlock = 0; allowManualRotation = true; allowManualFire = true; mTurretDelta.rot = Point3F(0.0f, 0.0f, 0.0f); mTurretDelta.rotVec = VectorF(0.0f, 0.0f, 0.0f); mTurretDelta.dt = 1; mRot = mTurretDelta.rot; mPitchAllowed = true; mHeadingAllowed = true; mPitchRate = -1; mHeadingRate = -1; mPitchUp = 0; mPitchDown = 0; mHeadingMax = mDegToRad(180.0f); mRespawn = false; mPitchThread = 0; mHeadingThread = 0; mSubclassTurretShapeHandlesScene = false; // For the Item class mSubclassItemHandlesScene = true; }
void ScatterSky::_getFogColor( ColorF *outColor ) { PROFILE_SCOPE( ScatterSky_GetFogColor ); VectorF scatterPos( 0, 0, 0 ); F32 sunBrightness = mSkyBrightness; mSkyBrightness *= 0.25f; F32 yaw = 0, pitch = 0, originalYaw = 0; VectorF fwd( 0, 1.0f, 0 ); MathUtils::getAnglesFromVector( fwd, yaw, pitch ); originalYaw = yaw; pitch = mDegToRad( 10.0f ); ColorF tmpColor( 0, 0, 0 ); U32 i = 0; for ( i = 0; i < 10; i++ ) { MathUtils::getVectorFromAngles( scatterPos, yaw, pitch ); scatterPos.x *= smEarthRadius + smAtmosphereRadius; scatterPos.y *= smEarthRadius + smAtmosphereRadius; scatterPos.z *= smEarthRadius + smAtmosphereRadius; scatterPos.y -= smEarthRadius; _getColor( scatterPos, &tmpColor ); (*outColor) += tmpColor; if ( i <= 5 ) yaw += mDegToRad( 5.0f ); else { originalYaw += mDegToRad( -5.0f ); yaw = originalYaw; } yaw = mFmod( yaw, M_2PI_F ); } if ( i > 0 ) (*outColor) /= i; mSkyBrightness = sunBrightness; }
void TurretShape::_applyLimits(Point3F& rot) { rot.x = mClampF(rot.x, mPitchUp, mPitchDown); if (mHeadingMax < mDegToRad(180.0f)) { rot.z = mClampF(rot.z, -mHeadingMax, mHeadingMax); } }
void ScatterSky::_conformLights() { _initCurves(); F32 val = mCurves[0].getVal( mTimeOfDay ); mNightInterpolant = 1.0f - val; VectorF lightDirection; F32 brightness; // Build the light direction from the azimuth and elevation. F32 yaw = mDegToRad(mClampF(mSunAzimuth,0,359)); F32 pitch = mDegToRad(mClampF(mSunElevation,-360,+360)); MathUtils::getVectorFromAngles(lightDirection, yaw, pitch); lightDirection.normalize(); mSunDir = -lightDirection; yaw = mDegToRad(mClampF(mMoonAzimuth,0,359)); pitch = mDegToRad(mClampF(mMoonElevation,-360,+360)); MathUtils::getVectorFromAngles( mMoonLightDir, yaw, pitch ); mMoonLightDir.normalize(); mMoonLightDir = -mMoonLightDir; brightness = mCurves[2].getVal( mTimeOfDay ); if ( mNightInterpolant >= 1.0f ) lightDirection = -mMoonLightDir; mLight->setDirection( -lightDirection ); mLight->setBrightness( brightness * mBrightness ); mLightDir = lightDirection; // Have to do interpolation // after the light direction is set // otherwise the sun color will be invalid. _interpolateColors(); mLight->setAmbient( mAmbientColor ); mLight->setColor( mSunColor ); mLight->setCastShadows( mCastShadows ); FogData fog = getSceneManager()->getFogData(); fog.color = mFogColor; getSceneManager()->setFogData( fog ); }
void EditTSCtrl::calcOrthoCamOffset(F32 mousex, F32 mousey, U8 modifier) { F32 camScale = 0.01f; switch(mDisplayType) { case DisplayTypeTop: mOrthoCamTrans.x -= mousex * mOrthoFOV * camScale; mOrthoCamTrans.y += mousey * mOrthoFOV * camScale; break; case DisplayTypeBottom: mOrthoCamTrans.x -= mousex * mOrthoFOV * camScale; mOrthoCamTrans.y -= mousey * mOrthoFOV * camScale; break; case DisplayTypeFront: mOrthoCamTrans.x += mousex * mOrthoFOV * camScale; mOrthoCamTrans.z += mousey * mOrthoFOV * camScale; break; case DisplayTypeBack: mOrthoCamTrans.x -= mousex * mOrthoFOV * camScale; mOrthoCamTrans.z += mousey * mOrthoFOV * camScale; break; case DisplayTypeLeft: mOrthoCamTrans.y += mousex * mOrthoFOV * camScale; mOrthoCamTrans.z += mousey * mOrthoFOV * camScale; break; case DisplayTypeRight: mOrthoCamTrans.y -= mousex * mOrthoFOV * camScale; mOrthoCamTrans.z += mousey * mOrthoFOV * camScale; break; case DisplayTypeIsometric: if(modifier & SI_PRIMARY_CTRL) { // NOTE: Maybe move the center of rotation code to right mouse down to avoid compound errors? F32 rot = mDegToRad(mousex); Point3F campos = (mRawCamPos + mOrthoCamTrans) - mIsoCamRotCenter; MatrixF mat(EulerF(0, 0, rot)); mat.mulP(campos); mOrthoCamTrans = (campos + mIsoCamRotCenter) - mRawCamPos; mIsoCamRot.z += rot; } else { mOrthoCamTrans.x -= mousex * mOrthoFOV * camScale * mCos(mIsoCamRot.z) - mousey * mOrthoFOV * camScale * mSin(mIsoCamRot.z); mOrthoCamTrans.y += mousex * mOrthoFOV * camScale * mSin(mIsoCamRot.z) + mousey * mOrthoFOV * camScale * mCos(mIsoCamRot.z); } break; } }
bool default_scan( const String &data, AngAxisF & result ) { if(StringUnit::getUnitCount(data," ") < 4) return false; dSscanf(data.c_str(),"%g %g %g %g", &result.axis.x,&result.axis.y,&result.axis.z,&result.angle); result.angle = mDegToRad(result.angle); return true; }
void Sun::_conformLights() { // Build the light direction from the azimuth and elevation. F32 yaw = mDegToRad(mClampF(mSunAzimuth,0,359)); F32 pitch = mDegToRad(mClampF(mSunElevation,-360,+360)); VectorF lightDirection; MathUtils::getVectorFromAngles(lightDirection, yaw, pitch); lightDirection.normalize(); mLight->setDirection( -lightDirection ); mLight->setBrightness( mBrightness ); // Now make sure the colors are within range. mLightColor.clamp(); mLight->setColor( mLightColor ); mLightAmbient.clamp(); mLight->setAmbient( mLightAmbient ); // Optimization... disable shadows if the ambient and // directional color are the same. bool castShadows = mLightColor != mLightAmbient && mCastShadows; mLight->setCastShadows( castShadows ); }
bool TurretShape::_outsideLimits(Point3F& rot) { if (rot.x < mPitchUp || rot.x > mPitchDown) return true; if (mHeadingMax < mDegToRad(180.0f)) { if (rot.z < -mHeadingMax || rot.z > mHeadingMax) return true; } return false; }
EditTSCtrl::EditTSCtrl() { mGizmoProfile = NULL; mGizmo = NULL; mRenderMissionArea = true; mMissionAreaFillColor.set(255,0,0,20); mMissionAreaFrameColor.set(255,0,0,128); mMissionAreaHeightAdjust = 5.0f; mConsoleFrameColor.set(255,0,0,255); mConsoleFillColor.set(255,0,0,120); mConsoleSphereLevel = 1; mConsoleCircleSegments = 32; mConsoleLineWidth = 1; mRightMousePassThru = true; mMiddleMousePassThru = true; mConsoleRendering = false; mDisplayType = DisplayTypePerspective; mOrthoFOV = 50.0f; mOrthoCamTrans.set(0.0f, 0.0f, 0.0f); mIsoCamAngle = mDegToRad(45.0f); mIsoCamRot = EulerF(0, 0, 0); mRenderGridPlane = true; mGridPlaneOriginColor = ColorI(255, 255, 255, 100); mGridPlaneColor = ColorI(102, 102, 102, 100); mGridPlaneMinorTickColor = ColorI(51, 51, 51, 100); mGridPlaneMinorTicks = 9; mGridPlaneSize = 1.0f; mGridPlaneSizePixelBias = 10.0f; mLastMousePos.set(0, 0); mAllowBorderMove = false; mMouseMoveBorder = 20; mMouseMoveSpeed = 0.1f; mLastBorderMoveTime = 0; mLeftMouseDown = false; mRightMouseDown = false; mMiddleMouseDown = false; mMiddleMouseTriggered = false; mMouseLeft = false; mBlendSB = NULL; }
void AdvancedLightBinManager::setupSGData( SceneData &data, const SceneRenderState* state, LightInfo *light ) { PROFILE_SCOPE( AdvancedLightBinManager_setupSGData ); data.lights[0] = light; data.ambientLightColor = state->getAmbientLightColor(); data.objTrans = &MatrixF::Identity; if ( light ) { if ( light->getType() == LightInfo::Point ) { // The point light volume gets some flat spots along // the perimiter mostly visible in the constant and // quadradic falloff modes. // // To account for them slightly increase the scale // instead of greatly increasing the polycount. mLightMat = light->getTransform(); mLightMat.scale( light->getRange() * 1.01f ); data.objTrans = &mLightMat; } else if ( light->getType() == LightInfo::Spot ) { mLightMat = light->getTransform(); // Rotate it to face down the -y axis. MatrixF scaleRotateTranslate( EulerF( M_PI_F / -2.0f, 0.0f, 0.0f ) ); // Calculate the radius based on the range and angle. F32 range = light->getRange().x; F32 radius = range * mSin( mDegToRad( light->getOuterConeAngle() ) * 0.5f ); // NOTE: This fudge makes the cone a little bigger // to remove the facet egde of the cone geometry. radius *= 1.1f; // Use the scale to distort the cone to // match our radius and range. scaleRotateTranslate.scale( Point3F( radius, radius, range ) ); // Apply the transform and set the position. mLightMat *= scaleRotateTranslate; mLightMat.setPosition( light->getPosition() ); data.objTrans = &mLightMat; } } }
void TurretShape::updateAnimation(F32 dt) { if (mRecoilThread) mShapeInstance->advanceTime(dt,mRecoilThread); if (mImageStateThread) mShapeInstance->advanceTime(dt,mImageStateThread); // Update any pitch and heading threads if (mPitchThread) { F32 d = mPitchDown - mPitchUp; if (!mIsZero(d)) { F32 pos = (mRot.x - mPitchUp) / d; mShapeInstance->setPos(mPitchThread, mClampF(pos, 0.0f, 1.0f)); } } if (mHeadingThread) { F32 pos = 0.0f; if (mHeadingMax < mDegToRad(180.0f)) { F32 d = mHeadingMax * 2.0f; if (!mIsZero(d)) { pos = (mRot.z + mHeadingMax) / d; } } else { pos = mRot.z / M_2PI; if (pos < 0.0f) { // We don't want negative rotations to simply mirror the // positive rotations but to animate into them as if -0.0 // is equivalent to 1.0. pos = mFmod(pos, 1.0f) + 1.0f; } if (pos > 1.0f) { pos = mFmod(pos, 1.0f); } } mShapeInstance->setPos(mHeadingThread, mClampF(pos, 0.0f, 1.0f)); } }
bool OculusVRDevice::process() { if(!mEnabled) return false; if(!getActive()) return false; //Build the maximum axis angle to be passed into the sensor process() F32 maxAxisRadius = mSin(mDegToRad(smMaximumAxisAngle)); // Process each sensor for(U32 i=0; i<mSensorDevices.size(); ++i) { mSensorDevices[i]->process(mDeviceType, smGenerateAngleAxisRotationEvents, smGenerateEulerRotationEvents, smGenerateRotationAsAxisEvents, maxAxisRadius); } return true; }
void AdvancedLightBinManager::LightMaterialInfo::setLightParameters( const LightInfo *lightInfo, const SceneRenderState* renderState, const MatrixF &worldViewOnly ) { MaterialParameters *matParams = matInstance->getMaterialParameters(); // Set color in the right format, set alpha to the luminance value for the color. ColorF col = lightInfo->getColor(); // TODO: The specularity control of the light // is being scaled by the overall lumiance. // // Not sure if this may be the source of our // bad specularity results maybe? // const Point3F colorToLumiance( 0.3576f, 0.7152f, 0.1192f ); F32 lumiance = mDot(*((const Point3F *)&lightInfo->getColor()), colorToLumiance ); col.alpha *= lumiance; matParams->setSafe( lightColor, col ); matParams->setSafe( lightBrightness, lightInfo->getBrightness() ); switch( lightInfo->getType() ) { case LightInfo::Vector: { VectorF lightDir = lightInfo->getDirection(); worldViewOnly.mulV(lightDir); lightDir.normalize(); matParams->setSafe( lightDirection, lightDir ); // Set small number for alpha since it represents existing specular in // the vector light. This prevents a divide by zero. ColorF ambientColor = renderState->getAmbientLightColor(); ambientColor.alpha = 0.00001f; matParams->setSafe( lightAmbient, ambientColor ); // If no alt color is specified, set it to the average of // the ambient and main color to avoid artifacts. // // TODO: Trilight disabled until we properly implement it // in the light info! // //ColorF lightAlt = lightInfo->getAltColor(); ColorF lightAlt( ColorF::BLACK ); // = lightInfo->getAltColor(); if ( lightAlt.red == 0.0f && lightAlt.green == 0.0f && lightAlt.blue == 0.0f ) lightAlt = (lightInfo->getColor() + renderState->getAmbientLightColor()) / 2.0f; ColorF trilightColor = lightAlt; matParams->setSafe(lightTrilight, trilightColor); } break; case LightInfo::Spot: { const F32 outerCone = lightInfo->getOuterConeAngle(); const F32 innerCone = getMin( lightInfo->getInnerConeAngle(), outerCone ); const F32 outerCos = mCos( mDegToRad( outerCone / 2.0f ) ); const F32 innerCos = mCos( mDegToRad( innerCone / 2.0f ) ); Point4F spotParams( outerCos, innerCos - outerCos, mCos( mDegToRad( outerCone ) ), 0.0f ); matParams->setSafe( lightSpotParams, spotParams ); VectorF lightDir = lightInfo->getDirection(); worldViewOnly.mulV(lightDir); lightDir.normalize(); matParams->setSafe( lightDirection, lightDir ); } // Fall through case LightInfo::Point: { const F32 radius = lightInfo->getRange().x; matParams->setSafe( lightRange, radius ); Point3F lightPos; worldViewOnly.mulP(lightInfo->getPosition(), &lightPos); matParams->setSafe( lightPosition, lightPos ); // Get the attenuation falloff ratio and normalize it. Point3F attenRatio = lightInfo->getExtended<ShadowMapParams>()->attenuationRatio; F32 total = attenRatio.x + attenRatio.y + attenRatio.z; if ( total > 0.0f ) attenRatio /= total; Point2F attenParams( ( 1.0f / radius ) * attenRatio.y, ( 1.0f / ( radius * radius ) ) * attenRatio.z ); matParams->setSafe( lightAttenuation, attenParams ); break; } default: AssertFatal( false, "Bad light type!" ); break; } }
bool LeapMotionDevice::process() { if(!mEnabled) return false; if(!getActive()) return false; //Con::printf("LeapMotionDevice::process()"); //Build the maximum hand axis angle to be passed into the LeapMotionDeviceData::setData() F32 maxHandAxisRadius = mSin(mDegToRad(smMaximumHandAxisAngle)); // Get a frame of data const Leap::Frame frame = mController->frame(); //const Leap::HandList hands = frame.hands(); //Con::printf("Frame: %lld Hands: %d Fingers: %d Tools: %d", (long long)frame.id(), hands.count(), frame.fingers().count(), frame.tools().count()); // Store the current data LeapMotionDeviceData* currentBuffer = (mPrevData == mDataBuffer[0]) ? mDataBuffer[1] : mDataBuffer[0]; currentBuffer->setData(frame, mPrevData, smKeepHandIndexPersistent, smKeepPointableIndexPersistent, maxHandAxisRadius); U32 diff = mPrevData->compare(currentBuffer); U32 metaDiff = mPrevData->compareMeta(currentBuffer); // Update the previous data pointers. We do this here in case someone calls our // console functions during one of the input events below. mPrevData = currentBuffer; // Send out any meta data if(metaDiff & LeapMotionDeviceData::METADIFF_FRAME_VALID_DATA) { // Frame valid change event INPUTMGR->buildInputEvent(mDeviceType, DEFAULT_MOTION_UNIT, SI_BUTTON, LM_FRAMEVALIDDATA, currentBuffer->mHasTrackingData ? SI_MAKE : SI_BREAK, currentBuffer->mHasTrackingData ? 1.0f : 0.0f); } // Send out any valid data if(currentBuffer->mDataSet && currentBuffer->mIsValid) { // Hands and their pointables if(smGenerateIndividualEvents) { for(U32 i=0; i<LeapMotionConstants::MaxHands; ++i) { if(currentBuffer->mHandValid[i]) { // Send out position INPUTMGR->buildInputEvent(mDeviceType, DEFAULT_MOTION_UNIT, SI_POS, LM_HAND[i], SI_MOVE, currentBuffer->mHandPosPoint[i]); // Send out rotation INPUTMGR->buildInputEvent(mDeviceType, DEFAULT_MOTION_UNIT, SI_ROT, LM_HANDROT[i], SI_MOVE, currentBuffer->mHandRotQuat[i]); // Pointables for hand for(U32 j=0; j<LeapMotionConstants::MaxPointablesPerHand; ++j) { if(currentBuffer->mPointableValid[i][j]) { // Send out position INPUTMGR->buildInputEvent(mDeviceType, DEFAULT_MOTION_UNIT, SI_POS, LM_HANDPOINTABLE[i][j], SI_MOVE, currentBuffer->mPointablePosPoint[i][j]); // Send out rotation INPUTMGR->buildInputEvent(mDeviceType, DEFAULT_MOTION_UNIT, SI_ROT, LM_HANDPOINTABLEROT[i][j], SI_MOVE, currentBuffer->mPointableRotQuat[i][j]); } } } } } // Single Hand as axis rotation if(smGenerateSingleHandRotationAsAxisEvents && diff & LeapMotionDeviceData::DIFF_HANDROTAXIS) { if(diff & LeapMotionDeviceData::DIFF_HANDROTAXISX) INPUTMGR->buildInputEvent(mDeviceType, DEFAULT_MOTION_UNIT, SI_AXIS, LM_HANDAXISX, SI_MOVE, currentBuffer->mHandRotAxis[0]); if(diff & LeapMotionDeviceData::DIFF_HANDROTAXISY) INPUTMGR->buildInputEvent(mDeviceType, DEFAULT_MOTION_UNIT, SI_AXIS, LM_HANDAXISY, SI_MOVE, currentBuffer->mHandRotAxis[1]); } } // Send out whole frame event, but only if the special frame group is defined if(smGenerateWholeFrameEvents && LeapMotionFrameStore::isFrameGroupDefined()) { S32 id = LEAPMOTIONFS->generateNewFrame(frame, maxHandAxisRadius); if(id != 0) { INPUTMGR->buildInputEvent(mDeviceType, DEFAULT_MOTION_UNIT, SI_INT, LM_FRAME, SI_VALUE, id); } } return true; }
void fxShapeReplicator::CreateShapes(void) { F32 HypX, HypY; F32 Angle; U32 RelocationRetry; Point3F ShapePosition; Point3F ShapeStart; Point3F ShapeEnd; Point3F ShapeScale; EulerF ShapeRotation; QuatF QRotation; bool CollisionResult; RayInfo RayEvent; TSShape* pShape; // Don't create shapes if we are hiding replications. if (mFieldData.mHideReplications) return; // Cannot continue without shapes! if (dStrcmp(mFieldData.mShapeFile, "") == 0) return; // Check that we can position somewhere! if (!( mFieldData.mAllowOnTerrain || mFieldData.mAllowStatics || mFieldData.mAllowOnWater)) { // Problem ... Con::warnf(ConsoleLogEntry::General, "[%s] - Could not place object, All alloweds are off!", getName()); // Return here. return; } // Check Shapes. AssertFatal(mCurrentShapeCount==0,"Shapes already present, this should not be possible!") // Check that we have a shape... if (!mFieldData.mShapeFile) return; // Set Seed. RandomGen.setSeed(mFieldData.mSeed); // Set shape vector. mReplicatedShapes.clear(); // Add shapes. for (U32 idx = 0; idx < mFieldData.mShapeCount; idx++) { fxShapeReplicatedStatic* fxStatic; // Create our static shape. fxStatic = new fxShapeReplicatedStatic(); // Set the 'shapeName' field. fxStatic->setField("shapeName", mFieldData.mShapeFile); // Is this Replicator on the Server? if (isServerObject()) // Yes, so stop it from Ghosting. (Hack, Hack, Hack!) fxStatic->touchNetFlags(Ghostable, false); else // No, so flag as ghost object. (Another damn Hack!) fxStatic->touchNetFlags(IsGhost, true); // Register the Object. if (!fxStatic->registerObject()) { // Problem ... Con::warnf(ConsoleLogEntry::General, "[%s] - Could not load shape file '%s'!", getName(), mFieldData.mShapeFile); // Destroy Shape. delete fxStatic; // Destroy existing hapes. DestroyShapes(); // Quit. return; } // Get Allocated Shape. pShape = fxStatic->getShape(); // Reset Relocation Retry. RelocationRetry = mFieldData.mShapeRetries; // Find it a home ... do { // Get the Replicator Position. ShapePosition = getPosition(); // Calculate a random offset HypX = RandomGen.randF(mFieldData.mInnerRadiusX, mFieldData.mOuterRadiusX); HypY = RandomGen.randF(mFieldData.mInnerRadiusY, mFieldData.mOuterRadiusY); Angle = RandomGen.randF(0, (F32)M_2PI); // Calcualte the new position. ShapePosition.x += HypX * mCos(Angle); ShapePosition.y += HypY * mSin(Angle); // Initialise RayCast Search Start/End Positions. ShapeStart = ShapeEnd = ShapePosition; ShapeStart.z = 2000.f; ShapeEnd.z= -2000.f; // Is this the Server? if (isServerObject()) // Perform Ray Cast Collision on Server Terrain. CollisionResult = gServerContainer.castRay(ShapeStart, ShapeEnd, FXREPLICATOR_COLLISION_MASK, &RayEvent); else // Perform Ray Cast Collision on Client Terrain. CollisionResult = gClientContainer.castRay( ShapeStart, ShapeEnd, FXREPLICATOR_COLLISION_MASK, &RayEvent); // Did we hit anything? if (CollisionResult) { // For now, let's pretend we didn't get a collision. CollisionResult = false; // Yes, so get it's type. U32 CollisionType = RayEvent.object->getTypeMask(); // Check Illegal Placements. if (((CollisionType & TerrainObjectType) && !mFieldData.mAllowOnTerrain) || ((CollisionType & StaticShapeObjectType) && !mFieldData.mAllowStatics) || ((CollisionType & WaterObjectType) && !mFieldData.mAllowOnWater) ) continue; // If we collided with water and are not allowing on the water surface then let's find the // terrain underneath and pass this on as the original collision else fail. // // NOTE:- We need to do this on the server/client as appropriate. if ((CollisionType & WaterObjectType) && !mFieldData.mAllowWaterSurface) { // Is this the Server? if (isServerObject()) { // Yes, so do it on the server container. if (!gServerContainer.castRay( ShapeStart, ShapeEnd, FXREPLICATOR_NOWATER_COLLISION_MASK, &RayEvent)) continue; } else { // No, so do it on the client container. if (!gClientContainer.castRay( ShapeStart, ShapeEnd, FXREPLICATOR_NOWATER_COLLISION_MASK, &RayEvent)) continue; } } // We passed with flying colours so carry on. CollisionResult = true; } // Invalidate if we are below Allowed Terrain Angle. if (RayEvent.normal.z < mSin(mDegToRad(90.0f-mFieldData.mAllowedTerrainSlope))) CollisionResult = false; // Wait until we get a collision. } while(!CollisionResult && --RelocationRetry); // Check for Relocation Problem. if (RelocationRetry > 0) { // Adjust Impact point. RayEvent.point.z += mFieldData.mOffsetZ; // Set New Position. ShapePosition = RayEvent.point; } else { // Warning. Con::warnf(ConsoleLogEntry::General, "[%s] - Could not find satisfactory position for shape '%s' on %s!", getName(), mFieldData.mShapeFile,isServerObject()?"Server":"Client"); // Unregister Object. fxStatic->unregisterObject(); // Destroy Shape. delete fxStatic; // Skip to next. continue; } // Get Shape Transform. MatrixF XForm = fxStatic->getTransform(); // Are we aligning to Terrain? if (mFieldData.mAlignToTerrain) { // Yes, so set rotation to Terrain Impact Normal. ShapeRotation = RayEvent.normal * mFieldData.mTerrainAlignment; } else { // No, so choose a new Rotation (in Radians). ShapeRotation.set( mDegToRad(RandomGen.randF(mFieldData.mShapeRotateMin.x, mFieldData.mShapeRotateMax.x)), mDegToRad(RandomGen.randF(mFieldData.mShapeRotateMin.y, mFieldData.mShapeRotateMax.y)), mDegToRad(RandomGen.randF(mFieldData.mShapeRotateMin.z, mFieldData.mShapeRotateMax.z))); } // Set Quaternion Roation. QRotation.set(ShapeRotation); // Set Transform Rotation. QRotation.setMatrix(&XForm); // Set Position. XForm.setColumn(3, ShapePosition); // Set Shape Position / Rotation. fxStatic->setTransform(XForm); // Choose a new Scale. ShapeScale.set( RandomGen.randF(mFieldData.mShapeScaleMin.x, mFieldData.mShapeScaleMax.x), RandomGen.randF(mFieldData.mShapeScaleMin.y, mFieldData.mShapeScaleMax.y), RandomGen.randF(mFieldData.mShapeScaleMin.z, mFieldData.mShapeScaleMax.z)); // Set Shape Scale. fxStatic->setScale(ShapeScale); // Lock it. fxStatic->setLocked(true); // Store Shape in Replicated Shapes Vector. //mReplicatedShapes[mCurrentShapeCount++] = fxStatic; mReplicatedShapes.push_back(fxStatic); } mCurrentShapeCount = mReplicatedShapes.size(); // Take first Timestamp. mLastRenderTime = Platform::getVirtualMilliseconds(); }
void FontRenderBatcher::render( F32 rot, const Point2F &offset ) { if( mLength == 0 ) return; GFX->setStateBlock(mFontSB); for(U32 i = 0; i < GFX->getNumSamplers(); i++) GFX->setTexture(i, NULL); MatrixF rotMatrix; bool doRotation = rot != 0.f; if(doRotation) rotMatrix.set( EulerF( 0.0, 0.0, mDegToRad( rot ) ) ); // Write verts out. U32 currentPt = 0; GFXVertexBufferHandle<GFXVertexPCT> verts(GFX, mLength * 6, GFXBufferTypeVolatile); verts.lock(); for( S32 i = 0; i < mSheets.size(); i++ ) { // Do some early outs... if(!mSheets[i]) continue; if(!mSheets[i]->numChars) continue; mSheets[i]->startVertex = currentPt; const GFXTextureObject *tex = mFont->getTextureHandle(i); for( S32 j = 0; j < mSheets[i]->numChars; j++ ) { // Get some general info to proceed with... const CharMarker &m = mSheets[i]->charIndex[j]; const PlatformFont::CharInfo &ci = mFont->getCharInfo( m.c ); // Where are we drawing it? F32 drawY = offset.y + mFont->getBaseline() - ci.yOrigin * TEXT_MAG; F32 drawX = offset.x + m.x + ci.xOrigin; // Figure some values. const F32 texWidth = (F32)tex->getWidth(); const F32 texHeight = (F32)tex->getHeight(); const F32 texLeft = (F32)(ci.xOffset) / texWidth; const F32 texRight = (F32)(ci.xOffset + ci.width) / texWidth; const F32 texTop = (F32)(ci.yOffset) / texHeight; const F32 texBottom = (F32)(ci.yOffset + ci.height) / texHeight; const F32 fillConventionOffset = GFX->getFillConventionOffset(); const F32 screenLeft = drawX - fillConventionOffset; const F32 screenRight = drawX - fillConventionOffset + ci.width * TEXT_MAG; const F32 screenTop = drawY - fillConventionOffset; const F32 screenBottom = drawY - fillConventionOffset + ci.height * TEXT_MAG; // Build our vertices. We NEVER read back from the buffer, that's // incredibly slow, so for rotation do it into tmp. This code is // ugly as sin. Point3F tmp; tmp.set( screenLeft, screenTop, 0.f ); if(doRotation) rotMatrix.mulP( tmp, &verts[currentPt].point); else verts[currentPt].point = tmp; verts[currentPt].color = m.color; verts[currentPt].texCoord.set( texLeft, texTop ); currentPt++; tmp.set( screenLeft, screenBottom, 0.f ); if(doRotation) rotMatrix.mulP( tmp, &verts[currentPt].point); else verts[currentPt].point = tmp; verts[currentPt].color = m.color; verts[currentPt].texCoord.set( texLeft, texBottom ); currentPt++; tmp.set( screenRight, screenBottom, 0.f ); if(doRotation) rotMatrix.mulP( tmp, &verts[currentPt].point); else verts[currentPt].point = tmp; verts[currentPt].color = m.color; verts[currentPt].texCoord.set( texRight, texBottom ); currentPt++; tmp.set( screenRight, screenBottom, 0.f ); if(doRotation) rotMatrix.mulP( tmp, &verts[currentPt].point); else verts[currentPt].point = tmp; verts[currentPt].color = m.color; verts[currentPt].texCoord.set( texRight, texBottom ); currentPt++; tmp.set( screenRight, screenTop, 0.f ); if(doRotation) rotMatrix.mulP( tmp, &verts[currentPt].point); else verts[currentPt].point = tmp; verts[currentPt].color = m.color; verts[currentPt].texCoord.set( texRight, texTop ); currentPt++; tmp.set( screenLeft, screenTop, 0.f ); if(doRotation) rotMatrix.mulP( tmp, &verts[currentPt].point); else verts[currentPt].point = tmp; verts[currentPt].color = m.color; verts[currentPt].texCoord.set( texLeft, texTop ); currentPt++; } } verts->unlock(); AssertFatal(currentPt <= mLength * 6, "FontRenderBatcher::render - too many verts for length of string!"); GFX->setVertexBuffer(verts); GFX->setupGenericShaders( GFXDevice::GSAddColorTexture ); // Now do an optimal render! for( S32 i = 0; i < mSheets.size(); i++ ) { if(!mSheets[i]) continue; if(!mSheets[i]->numChars ) continue; GFX->setTexture( 0, mFont->getTextureHandle(i) ); GFX->drawPrimitive(GFXTriangleList, mSheets[i]->startVertex, mSheets[i]->numChars * 2); } }
bool EditTSCtrl::processCameraQuery(CameraQuery * query) { if(mDisplayType == DisplayTypePerspective) { query->ortho = false; } else { query->ortho = true; } if (getCameraTransform(&query->cameraMatrix)) { query->farPlane = gClientSceneGraph->getVisibleDistance() * smVisibleDistanceScale; query->nearPlane = gClientSceneGraph->getNearClip(); query->fov = mDegToRad(smCamFOV); if(query->ortho) { MatrixF camRot(true); const F32 camBuffer = 1.0f; Point3F camPos = query->cameraMatrix.getPosition(); F32 isocamplanedist = 0.0f; if(mDisplayType == DisplayTypeIsometric) { const RectI& vp = GFX->getViewport(); isocamplanedist = 0.25 * vp.extent.y * mSin(mIsoCamAngle); } // Calculate the scene bounds Box3F sceneBounds; computeSceneBounds(sceneBounds); if(!sceneBounds.isValidBox()) { sceneBounds.maxExtents = camPos + smMinSceneBounds; sceneBounds.minExtents = camPos - smMinSceneBounds; } else { query->farPlane = getMax(smMinSceneBounds.x * 2.0f, (sceneBounds.maxExtents - sceneBounds.minExtents).len() + camBuffer * 2.0f + isocamplanedist); } mRawCamPos = camPos; camPos += mOrthoCamTrans; switch(mDisplayType) { case DisplayTypeTop: camRot.setColumn(0, Point3F(1.0, 0.0, 0.0)); camRot.setColumn(1, Point3F(0.0, 0.0, -1.0)); camRot.setColumn(2, Point3F(0.0, 1.0, 0.0)); camPos.z = getMax(camPos.z + smMinSceneBounds.z, sceneBounds.maxExtents.z + camBuffer); break; case DisplayTypeBottom: camRot.setColumn(0, Point3F(1.0, 0.0, 0.0)); camRot.setColumn(1, Point3F(0.0, 0.0, 1.0)); camRot.setColumn(2, Point3F(0.0, -1.0, 0.0)); camPos.z = getMin(camPos.z - smMinSceneBounds.z, sceneBounds.minExtents.z - camBuffer); break; case DisplayTypeFront: camRot.setColumn(0, Point3F(-1.0, 0.0, 0.0)); camRot.setColumn(1, Point3F( 0.0, -1.0, 0.0)); camRot.setColumn(2, Point3F( 0.0, 0.0, 1.0)); camPos.y = getMax(camPos.y + smMinSceneBounds.y, sceneBounds.maxExtents.y + camBuffer); break; case DisplayTypeBack: camRot.setColumn(0, Point3F(1.0, 0.0, 0.0)); camRot.setColumn(1, Point3F(0.0, 1.0, 0.0)); camRot.setColumn(2, Point3F(0.0, 0.0, 1.0)); camPos.y = getMin(camPos.y - smMinSceneBounds.y, sceneBounds.minExtents.y - camBuffer); break; case DisplayTypeLeft: camRot.setColumn(0, Point3F( 0.0, -1.0, 0.0)); camRot.setColumn(1, Point3F( 1.0, 0.0, 0.0)); camRot.setColumn(2, Point3F( 0.0, 0.0, 1.0)); camPos.x = getMin(camPos.x - smMinSceneBounds.x, sceneBounds.minExtents.x - camBuffer); break; case DisplayTypeRight: camRot.setColumn(0, Point3F( 0.0, 1.0, 0.0)); camRot.setColumn(1, Point3F(-1.0, 0.0, 0.0)); camRot.setColumn(2, Point3F( 0.0, 0.0, 1.0)); camPos.x = getMax(camPos.x + smMinSceneBounds.x, sceneBounds.maxExtents.x + camBuffer); break; case DisplayTypeIsometric: camPos.z = sceneBounds.maxExtents.z + camBuffer + isocamplanedist; MatrixF angle(EulerF(mIsoCamAngle, 0, 0)); MatrixF rot(mIsoCamRot); camRot.mul(rot, angle); break; } query->cameraMatrix = camRot; query->cameraMatrix.setPosition(camPos); query->fov = mOrthoFOV; } smCamMatrix = query->cameraMatrix; smCamMatrix.getColumn(3,&smCamPos); smCamOrtho = query->ortho; smCamNearPlane = query->nearPlane; return true; } return false; }
void LightManager::_update4LightConsts( const SceneData &sgData, GFXShaderConstHandle *lightPositionSC, GFXShaderConstHandle *lightDiffuseSC, GFXShaderConstHandle *lightAmbientSC, GFXShaderConstHandle *lightInvRadiusSqSC, GFXShaderConstHandle *lightSpotDirSC, GFXShaderConstHandle *lightSpotAngleSC, GFXShaderConstHandle *lightSpotFalloffSC, GFXShaderConstBuffer *shaderConsts ) { PROFILE_SCOPE( LightManager_Update4LightConsts ); // Skip over gathering lights if we don't have to! if ( lightPositionSC->isValid() || lightDiffuseSC->isValid() || lightInvRadiusSqSC->isValid() || lightSpotDirSC->isValid() || lightSpotAngleSC->isValid() || lightSpotFalloffSC->isValid() ) { PROFILE_SCOPE( LightManager_Update4LightConsts_setLights ); static AlignedArray<Point4F> lightPositions( 3, sizeof( Point4F ) ); static AlignedArray<Point4F> lightSpotDirs( 3, sizeof( Point4F ) ); static AlignedArray<Point4F> lightColors( 4, sizeof( Point4F ) ); static Point4F lightInvRadiusSq; static Point4F lightSpotAngle; static Point4F lightSpotFalloff; F32 range; // Need to clear the buffers so that we don't leak // lights from previous passes or have NaNs. dMemset( lightPositions.getBuffer(), 0, lightPositions.getBufferSize() ); dMemset( lightSpotDirs.getBuffer(), 0, lightSpotDirs.getBufferSize() ); dMemset( lightColors.getBuffer(), 0, lightColors.getBufferSize() ); lightInvRadiusSq = Point4F::Zero; lightSpotAngle.set( -1.0f, -1.0f, -1.0f, -1.0f ); lightSpotFalloff.set( F32_MAX, F32_MAX, F32_MAX, F32_MAX ); // Gather the data for the first 4 lights. const LightInfo *light; for ( U32 i=0; i < 4; i++ ) { light = sgData.lights[i]; if ( !light ) break; // The light positions and spot directions are // in SoA order to make optimal use of the GPU. const Point3F &lightPos = light->getPosition(); lightPositions[0][i] = lightPos.x; lightPositions[1][i] = lightPos.y; lightPositions[2][i] = lightPos.z; const VectorF &lightDir = light->getDirection(); lightSpotDirs[0][i] = lightDir.x; lightSpotDirs[1][i] = lightDir.y; lightSpotDirs[2][i] = lightDir.z; if ( light->getType() == LightInfo::Spot ) { lightSpotAngle[i] = mCos( mDegToRad( light->getOuterConeAngle() / 2.0f ) ); lightSpotFalloff[i] = 1.0f / getMax( F32_MIN, mCos( mDegToRad( light->getInnerConeAngle() / 2.0f ) ) - lightSpotAngle[i] ); } // Prescale the light color by the brightness to // avoid doing this in the shader. lightColors[i] = Point4F(light->getColor()) * light->getBrightness(); // We need 1 over range^2 here. range = light->getRange().x; lightInvRadiusSq[i] = 1.0f / ( range * range ); } shaderConsts->setSafe( lightPositionSC, lightPositions ); shaderConsts->setSafe( lightDiffuseSC, lightColors ); shaderConsts->setSafe( lightInvRadiusSqSC, lightInvRadiusSq ); shaderConsts->setSafe( lightSpotDirSC, lightSpotDirs ); shaderConsts->setSafe( lightSpotAngleSC, lightSpotAngle ); shaderConsts->setSafe( lightSpotFalloffSC, lightSpotFalloff ); } // Setup the ambient lighting from the first // light which is the directional light if // one exists at all in the scene. if ( lightAmbientSC->isValid() ) shaderConsts->set( lightAmbientSC, sgData.ambientLightColor ); }
void TSLastDetail::_update() { // We're gonna render... make sure we can. bool sceneBegun = GFX->canCurrentlyRender(); if ( !sceneBegun ) GFX->beginScene(); _validateDim(); Vector<GBitmap*> bitmaps; Vector<GBitmap*> normalmaps; // We need to create our own instance to render with. TSShapeInstance *shape = new TSShapeInstance( mShape, true ); // Animate the shape once. shape->animate( mDl ); // So we don't have to change it everywhere. const GFXFormat format = GFXFormatR8G8B8A8; S32 imposterCount = ( ((2*mNumPolarSteps) + 1 ) * mNumEquatorSteps ) + ( mIncludePoles ? 2 : 0 ); // Figure out the optimal texture size. Point2I texSize( smMaxTexSize, smMaxTexSize ); while ( true ) { Point2I halfSize( texSize.x / 2, texSize.y / 2 ); U32 count = ( halfSize.x / mDim ) * ( halfSize.y / mDim ); if ( count < imposterCount ) { // Try half of the height. count = ( texSize.x / mDim ) * ( halfSize.y / mDim ); if ( count >= imposterCount ) texSize.y = halfSize.y; break; } texSize = halfSize; } GBitmap *imposter = NULL; GBitmap *normalmap = NULL; GBitmap destBmp( texSize.x, texSize.y, true, format ); GBitmap destNormal( texSize.x, texSize.y, true, format ); U32 mipLevels = destBmp.getNumMipLevels(); ImposterCapture *imposterCap = new ImposterCapture(); F32 equatorStepSize = M_2PI_F / (F32)mNumEquatorSteps; static const MatrixF topXfm( EulerF( -M_PI_F / 2.0f, 0, 0 ) ); static const MatrixF bottomXfm( EulerF( M_PI_F / 2.0f, 0, 0 ) ); MatrixF angMat; F32 polarStepSize = 0.0f; if ( mNumPolarSteps > 0 ) polarStepSize = -( 0.5f * M_PI_F - mDegToRad( mPolarAngle ) ) / (F32)mNumPolarSteps; PROFILE_START(TSLastDetail_snapshots); S32 currDim = mDim; for ( S32 mip = 0; mip < mipLevels; mip++ ) { if ( currDim < 1 ) currDim = 1; dMemset( destBmp.getWritableBits(mip), 0, destBmp.getWidth(mip) * destBmp.getHeight(mip) * GFXFormat_getByteSize( format ) ); dMemset( destNormal.getWritableBits(mip), 0, destNormal.getWidth(mip) * destNormal.getHeight(mip) * GFXFormat_getByteSize( format ) ); bitmaps.clear(); normalmaps.clear(); F32 rotX = 0.0f; if ( mNumPolarSteps > 0 ) rotX = -( mDegToRad( mPolarAngle ) - 0.5f * M_PI_F ); // We capture the images in a particular order which must // match the order expected by the imposter renderer. imposterCap->begin( shape, mDl, currDim, mRadius, mCenter ); for ( U32 j=0; j < (2 * mNumPolarSteps + 1); j++ ) { F32 rotZ = -M_PI_F / 2.0f; for ( U32 k=0; k < mNumEquatorSteps; k++ ) { angMat.mul( MatrixF( EulerF( rotX, 0, 0 ) ), MatrixF( EulerF( 0, 0, rotZ ) ) ); imposterCap->capture( angMat, &imposter, &normalmap ); bitmaps.push_back( imposter ); normalmaps.push_back( normalmap ); rotZ += equatorStepSize; } rotX += polarStepSize; if ( mIncludePoles ) { imposterCap->capture( topXfm, &imposter, &normalmap ); bitmaps.push_back(imposter); normalmaps.push_back( normalmap ); imposterCap->capture( bottomXfm, &imposter, &normalmap ); bitmaps.push_back( imposter ); normalmaps.push_back( normalmap ); } } imposterCap->end(); Point2I texSize( destBmp.getWidth(mip), destBmp.getHeight(mip) ); // Ok... pack in bitmaps till we run out. for ( S32 y=0; y+currDim <= texSize.y; ) { for ( S32 x=0; x+currDim <= texSize.x; ) { // Copy the next bitmap to the dest texture. GBitmap* bmp = bitmaps.first(); bitmaps.pop_front(); destBmp.copyRect( bmp, RectI( 0, 0, currDim, currDim ), Point2I( x, y ), 0, mip ); delete bmp; // Copy the next normal to the dest texture. GBitmap* normalmap = normalmaps.first(); normalmaps.pop_front(); destNormal.copyRect( normalmap, RectI( 0, 0, currDim, currDim ), Point2I( x, y ), 0, mip ); delete normalmap; // Did we finish? if ( bitmaps.empty() ) break; x += currDim; } // Did we finish? if ( bitmaps.empty() ) break; y += currDim; } // Next mip... currDim /= 2; } PROFILE_END(); // TSLastDetail_snapshots delete imposterCap; delete shape; // Should we dump the images? if ( Con::getBoolVariable( "$TSLastDetail::dumpImposters", false ) ) { String imposterPath = mCachePath + ".imposter.png"; String normalsPath = mCachePath + ".imposter_normals.png"; FileStream stream; if ( stream.open( imposterPath, Torque::FS::File::Write ) ) destBmp.writeBitmap( "png", stream ); stream.close(); if ( stream.open( normalsPath, Torque::FS::File::Write ) ) destNormal.writeBitmap( "png", stream ); stream.close(); } // DEBUG: Some code to force usage of a test image. //GBitmap* tempMap = GBitmap::load( "./forest/data/test1234.png" ); //tempMap->extrudeMipLevels(); //mTexture.set( tempMap, &GFXDefaultStaticDiffuseProfile, false ); //delete tempMap; DDSFile *ddsDest = DDSFile::createDDSFileFromGBitmap( &destBmp ); DDSUtil::squishDDS( ddsDest, GFXFormatDXT3 ); DDSFile *ddsNormals = DDSFile::createDDSFileFromGBitmap( &destNormal ); DDSUtil::squishDDS( ddsNormals, GFXFormatDXT5 ); // Finally save the imposters to disk. FileStream fs; if ( fs.open( _getDiffuseMapPath(), Torque::FS::File::Write ) ) { ddsDest->write( fs ); fs.close(); } if ( fs.open( _getNormalMapPath(), Torque::FS::File::Write ) ) { ddsNormals->write( fs ); fs.close(); } delete ddsDest; delete ddsNormals; // If we did a begin then end it now. if ( !sceneBegun ) GFX->endScene(); }
void ForestWind::processTick() { PROFILE_SCOPE( ForestWind_ProcessTick ); const F32 deltaTime = 0.032f; const U32 simTime = Sim::getCurrentTime(); Point2F finalVec( 0, 0 ); Point2F windDir( mParent->mWindDirection.x, mParent->mWindDirection.y ); if ( mLastGustTime < simTime ) { Point2F turbVec( 0, 0 ); if ( mLastGustTime < simTime + (mParent->mWindTurbulenceFrequency * 1000.0f) ) turbVec = (mRandom.randF() * mParent->mWindTurbulenceStrength) * windDir; mLastGustTime = simTime + (mParent->mWindGustFrequency * 1000.0f); Point2F gustVec = (mRandom.randF() * mParent->mWindGustStrength + mRandom.randF() * mParent->mWindGustWobbleStrength) * windDir; finalVec += gustVec + turbVec; //finalVec.normalizeSafe(); } //bool rotationChange = false; if ( mLastYawTime < simTime ) { mLastYawTime = simTime + (mParent->mWindGustYawFrequency * 1000.0f); F32 rotateAmt = mRandom.randF() * mParent->mWindGustYawAngle + mRandom.randF() * mParent->mWindGustWobbleStrength; if ( mRandom.randF() <= 0.5f ) rotateAmt = -rotateAmt; rotateAmt = mDegToRad( rotateAmt ); if ( rotateAmt > M_2PI_F ) rotateAmt -= M_2PI_F; else if ( rotateAmt < -M_2PI_F ) rotateAmt += M_2PI_F; mTargetYawAngle = rotateAmt; //finalVec.rotate( rotateAmt ); mCurrentTarget.rotate( rotateAmt ); } //mCurrentTarget.normalizeSafe(); if ( mCurrentTarget.isZero() || mCurrentInterp >= 1.0f ) { mCurrentInterp = 0; mCurrentTarget.set( 0, 0 ); Point2F windDir( mDirection.x, mDirection.y ); windDir.normalizeSafe(); mCurrentTarget = finalVec + windDir; } else { mCurrentInterp += deltaTime; mCurrentInterp = mClampF( mCurrentInterp, 0.0f, 1.0f ); mDirection.interpolate( mDirection, Point3F( mCurrentTarget.x, mCurrentTarget.y, 0 ), mCurrentInterp ); //F32 rotateAmt = mLerp( 0, mTargetYawAngle, mCurrentInterp ); //mTargetYawAngle -= rotateAmt; //Point2F dir( mDirection.x, mDirection.y ); //if ( mTargetYawAngle > 0.0f ) // dir.rotate( rotateAmt ); //mDirection.set( dir.x, dir.y, 0 ); } }