RageMatrix RageLookAt( float eyex, float eyey, float eyez, float centerx, float centery, float centerz, float upx, float upy, float upz ) { RageVector3 Z(eyex - centerx, eyey - centery, eyez - centerz); RageVec3Normalize(&Z, &Z); RageVector3 Y(upx, upy, upz); RageVector3 X( Y[1] * Z[2] - Y[2] * Z[1], -Y[0] * Z[2] + Y[2] * Z[0], Y[0] * Z[1] - Y[1] * Z[0]); Y = RageVector3( Z[1] * X[2] - Z[2] * X[1], -Z[0] * X[2] + Z[2] * X[0], Z[0] * X[1] - Z[1] * X[0] ); RageVec3Normalize(&X, &X); RageVec3Normalize(&Y, &Y); RageMatrix mat( X[0], Y[0], Z[0], 0, X[1], Y[1], Z[1], 0, X[2], Y[2], Z[2], 0, 0, 0, 0, 1 ); RageMatrix mat2; RageMatrixTranslation(&mat2, -eyex, -eyey, -eyez); RageMatrix ret; RageMatrixMultiply(&ret, &mat, &mat2); return ret; }
void BGAnimationLayer::LoadFromAniLayerFile( const RString& sPath ) { /* Generic BGAs are new. Animation directories with no INI are old and obsolete. * Don't combine them. */ RString lcPath = sPath; lcPath.MakeLower(); if( lcPath.find("usesongbg") != RString::npos ) { const Song* pSong = GAMESTATE->m_pCurSong; RString sSongBGPath; if( pSong && pSong->HasBackground() ) sSongBGPath = pSong->GetBackgroundPath(); else sSongBGPath = THEME->GetPathG("Common","fallback background"); Sprite* pSprite = new Sprite; pSprite->Load( Sprite::SongBGTexture(sSongBGPath) ); pSprite->StretchTo( FullScreenRectF ); this->AddChild( pSprite ); return; // this will ignore other effects in the file name } enum Effect { EFFECT_CENTER, EFFECT_STRETCH_STILL, EFFECT_STRETCH_SCROLL_LEFT, EFFECT_STRETCH_SCROLL_RIGHT, EFFECT_STRETCH_SCROLL_UP, EFFECT_STRETCH_SCROLL_DOWN, EFFECT_STRETCH_WATER, EFFECT_STRETCH_BUBBLE, EFFECT_STRETCH_TWIST, EFFECT_STRETCH_SPIN, EFFECT_PARTICLES_SPIRAL_OUT, EFFECT_PARTICLES_SPIRAL_IN, EFFECT_PARTICLES_FLOAT_UP, EFFECT_PARTICLES_FLOAT_DOWN, EFFECT_PARTICLES_FLOAT_LEFT, EFFECT_PARTICLES_FLOAT_RIGHT, EFFECT_PARTICLES_BOUNCE, EFFECT_TILE_STILL, EFFECT_TILE_SCROLL_LEFT, EFFECT_TILE_SCROLL_RIGHT, EFFECT_TILE_SCROLL_UP, EFFECT_TILE_SCROLL_DOWN, EFFECT_TILE_FLIP_X, EFFECT_TILE_FLIP_Y, EFFECT_TILE_PULSE, NUM_EFFECTS, // leave this at the end EFFECT_INVALID }; const RString EFFECT_STRING[NUM_EFFECTS] = { "center", "stretchstill", "stretchscrollleft", "stretchscrollright", "stretchscrollup", "stretchscrolldown", "stretchwater", "stretchbubble", "stretchtwist", "stretchspin", "particlesspiralout", "particlesspiralin", "particlesfloatup", "particlesfloatdown", "particlesfloatleft", "particlesfloatright", "particlesbounce", "tilestill", "tilescrollleft", "tilescrollright", "tilescrollup", "tilescrolldown", "tileflipx", "tileflipy", "tilepulse", }; Effect effect = EFFECT_CENTER; for( int i=0; i<NUM_EFFECTS; i++ ) if( lcPath.find(EFFECT_STRING[i]) != string::npos ) effect = (Effect)i; switch( effect ) { case EFFECT_CENTER: { m_Type = TYPE_SPRITE; Sprite* pSprite = new Sprite; this->AddChild( pSprite ); pSprite->Load( sPath ); pSprite->SetXY( SCREEN_CENTER_X, SCREEN_CENTER_Y ); } break; case EFFECT_STRETCH_STILL: case EFFECT_STRETCH_SCROLL_LEFT: case EFFECT_STRETCH_SCROLL_RIGHT: case EFFECT_STRETCH_SCROLL_UP: case EFFECT_STRETCH_SCROLL_DOWN: case EFFECT_STRETCH_WATER: case EFFECT_STRETCH_BUBBLE: case EFFECT_STRETCH_TWIST: { m_Type = TYPE_SPRITE; Sprite* pSprite = new Sprite; this->AddChild( pSprite ); RageTextureID ID(sPath); ID.bStretch = true; pSprite->Load( Sprite::SongBGTexture(ID) ); pSprite->StretchTo( FullScreenRectF ); pSprite->SetCustomTextureRect( RectF(0,0,1,1) ); switch( effect ) { case EFFECT_STRETCH_SCROLL_LEFT: m_fTexCoordVelocityX = +0.5f; m_fTexCoordVelocityY = 0; break; case EFFECT_STRETCH_SCROLL_RIGHT: m_fTexCoordVelocityX = -0.5f; m_fTexCoordVelocityY = 0; break; case EFFECT_STRETCH_SCROLL_UP: m_fTexCoordVelocityX = 0; m_fTexCoordVelocityY = +0.5f; break; case EFFECT_STRETCH_SCROLL_DOWN: m_fTexCoordVelocityX = 0; m_fTexCoordVelocityY = -0.5f; break; default: break; } } break; case EFFECT_STRETCH_SPIN: { m_Type = TYPE_SPRITE; Sprite* pSprite = new Sprite; this->AddChild( pSprite ); pSprite->Load( Sprite::SongBGTexture(sPath) ); const RectF StretchedFullScreenRectF( FullScreenRectF.left-200, FullScreenRectF.top-200, FullScreenRectF.right+200, FullScreenRectF.bottom+200 ); pSprite->ScaleToCover( StretchedFullScreenRectF ); pSprite->SetEffectSpin( RageVector3(0,0,60) ); } break; case EFFECT_PARTICLES_SPIRAL_OUT: case EFFECT_PARTICLES_SPIRAL_IN: case EFFECT_PARTICLES_FLOAT_UP: case EFFECT_PARTICLES_FLOAT_DOWN: case EFFECT_PARTICLES_FLOAT_LEFT: case EFFECT_PARTICLES_FLOAT_RIGHT: case EFFECT_PARTICLES_BOUNCE: { m_Type = TYPE_PARTICLES; Sprite s; s.Load( sPath ); int iSpriteArea = int( s.GetUnzoomedWidth()*s.GetUnzoomedHeight() ); const int iMaxArea = int(SCREEN_WIDTH*SCREEN_HEIGHT); int iNumParticles = iMaxArea / iSpriteArea; iNumParticles = min( iNumParticles, MAX_SPRITES ); for( int i=0; i<iNumParticles; i++ ) { Sprite* pSprite = new Sprite; this->AddChild( pSprite ); pSprite->Load( sPath ); pSprite->SetZoom( 0.7f + 0.6f*i/(float)iNumParticles ); switch( effect ) { case EFFECT_PARTICLES_BOUNCE: pSprite->SetX( randomf( GetGuardRailLeft(pSprite), GetGuardRailRight(pSprite) ) ); pSprite->SetY( randomf( GetGuardRailTop(pSprite), GetGuardRailBottom(pSprite) ) ); break; default: pSprite->SetX( randomf( GetOffScreenLeft(pSprite), GetOffScreenRight(pSprite) ) ); pSprite->SetY( randomf( GetOffScreenTop(pSprite), GetOffScreenBottom(pSprite) ) ); break; } switch( effect ) { case EFFECT_PARTICLES_FLOAT_UP: case EFFECT_PARTICLES_SPIRAL_OUT: m_vParticleVelocity.push_back( RageVector3( 0, -PARTICLE_SPEED*pSprite->GetZoom(), 0 ) ); break; case EFFECT_PARTICLES_FLOAT_DOWN: case EFFECT_PARTICLES_SPIRAL_IN: m_vParticleVelocity.push_back( RageVector3( 0, PARTICLE_SPEED*pSprite->GetZoom(), 0 ) ); break; case EFFECT_PARTICLES_FLOAT_LEFT: m_vParticleVelocity.push_back( RageVector3( -PARTICLE_SPEED*pSprite->GetZoom(), 0, 0 ) ); break; case EFFECT_PARTICLES_FLOAT_RIGHT: m_vParticleVelocity.push_back( RageVector3( +PARTICLE_SPEED*pSprite->GetZoom(), 0, 0 ) ); break; case EFFECT_PARTICLES_BOUNCE: m_bParticlesBounce = true; pSprite->SetZoom( 1 ); m_vParticleVelocity.push_back( RageVector3( randomf(), randomf(), 0 ) ); RageVec3Normalize( &m_vParticleVelocity[i], &m_vParticleVelocity[i] ); m_vParticleVelocity[i].x *= PARTICLE_SPEED; m_vParticleVelocity[i].y *= PARTICLE_SPEED; break; default: FAIL_M(ssprintf("Unrecognized layer effect: %i", effect)); } } } break; case EFFECT_TILE_STILL: case EFFECT_TILE_SCROLL_LEFT: case EFFECT_TILE_SCROLL_RIGHT: case EFFECT_TILE_SCROLL_UP: case EFFECT_TILE_SCROLL_DOWN: case EFFECT_TILE_FLIP_X: case EFFECT_TILE_FLIP_Y: case EFFECT_TILE_PULSE: { m_Type = TYPE_TILES; RageTextureID ID(sPath); ID.bStretch = true; Sprite s; s.Load( ID ); m_iNumTilesWide = 2+int(SCREEN_WIDTH /s.GetUnzoomedWidth()); m_iNumTilesWide = min( m_iNumTilesWide, MAX_TILES_WIDE ); m_iNumTilesHigh = 2+int(SCREEN_HEIGHT/s.GetUnzoomedHeight()); m_iNumTilesHigh = min( m_iNumTilesHigh, MAX_TILES_HIGH ); m_fTilesStartX = s.GetUnzoomedWidth() / 2; m_fTilesStartY = s.GetUnzoomedHeight() / 2; m_fTilesSpacingX = s.GetUnzoomedWidth(); m_fTilesSpacingY = s.GetUnzoomedHeight(); for( int x=0; x<m_iNumTilesWide; x++ ) { for( int y=0; y<m_iNumTilesHigh; y++ ) { Sprite* pSprite = new Sprite; this->AddChild( pSprite ); pSprite->Load( ID ); pSprite->SetTextureWrapping( true ); // gets rid of some "cracks" switch( effect ) { case EFFECT_TILE_STILL: break; case EFFECT_TILE_SCROLL_LEFT: m_fTileVelocityX = -PARTICLE_SPEED; break; case EFFECT_TILE_SCROLL_RIGHT: m_fTileVelocityX = +PARTICLE_SPEED; break; case EFFECT_TILE_SCROLL_UP: m_fTileVelocityY = -PARTICLE_SPEED; break; case EFFECT_TILE_SCROLL_DOWN: m_fTileVelocityY = +PARTICLE_SPEED; break; case EFFECT_TILE_FLIP_X: pSprite->SetEffectSpin( RageVector3(180,0,0) ); break; case EFFECT_TILE_FLIP_Y: pSprite->SetEffectSpin( RageVector3(0,180,0) ); break; case EFFECT_TILE_PULSE: pSprite->SetEffectPulse( 1, 0.3f, 1.f ); break; default: FAIL_M(ssprintf("Not a tile effect: %i", effect)); } } } } break; default: FAIL_M(ssprintf("Unrecognized layer effect: %i", effect)); } RString sHint = sPath; sHint.MakeLower(); if( sHint.find("cyclecolor") != RString::npos ) for( unsigned i=0; i<m_SubActors.size(); i++ ) m_SubActors[i]->SetEffectRainbow( 5 ); if( sHint.find("cyclealpha") != RString::npos ) for( unsigned i=0; i<m_SubActors.size(); i++ ) m_SubActors[i]->SetEffectDiffuseShift( 2, RageColor(1,1,1,1), RageColor(1,1,1,0) ); if( sHint.find("startonrandomframe") != RString::npos ) for( unsigned i=0; i<m_SubActors.size(); i++ ) m_SubActors[i]->SetState( RandomInt(m_SubActors[i]->GetNumStates()) ); if( sHint.find("dontanimate") != RString::npos ) for( unsigned i=0; i<m_SubActors.size(); i++ ) m_SubActors[i]->StopAnimating(); if( sHint.find("add") != RString::npos ) for( unsigned i=0; i<m_SubActors.size(); i++ ) m_SubActors[i]->SetBlendMode( BLEND_ADD ); }
void BGAnimationLayer::LoadFromNode( const XNode* pNode ) { { bool bCond; if( pNode->GetAttrValue("Condition", bCond) && !bCond ) return; } bool bStretch = false; { RString type = "sprite"; pNode->GetAttrValue( "Type", type ); type.MakeLower(); /* The preferred way of stretching a sprite to fit the screen is "Type=sprite" * and "stretch=1". "type=1" is for backwards-compatibility. */ pNode->GetAttrValue( "Stretch", bStretch ); // Check for string match first, then do integer match. // "if(StringType(type)==0)" was matching against all string matches. // -Chris if( type.EqualsNoCase("sprite") ) { m_Type = TYPE_SPRITE; } else if( type.EqualsNoCase("particles") ) { m_Type = TYPE_PARTICLES; } else if( type.EqualsNoCase("tiles") ) { m_Type = TYPE_TILES; } else if( StringToInt(type) == 1 ) { m_Type = TYPE_SPRITE; bStretch = true; } else if( StringToInt(type) == 2 ) { m_Type = TYPE_PARTICLES; } else if( StringToInt(type) == 3 ) { m_Type = TYPE_TILES; } else { m_Type = TYPE_SPRITE; } } pNode->GetAttrValue( "FOV", m_fFOV ); pNode->GetAttrValue( "Lighting", m_bLighting ); pNode->GetAttrValue( "TexCoordVelocityX", m_fTexCoordVelocityX ); pNode->GetAttrValue( "TexCoordVelocityY", m_fTexCoordVelocityY ); // compat: pNode->GetAttrValue( "StretchTexCoordVelocityX", m_fTexCoordVelocityX ); pNode->GetAttrValue( "StretchTexCoordVelocityY", m_fTexCoordVelocityY ); // particle and tile stuff float fZoomMin = 1; float fZoomMax = 1; pNode->GetAttrValue( "ZoomMin", fZoomMin ); pNode->GetAttrValue( "ZoomMax", fZoomMax ); float fVelocityXMin = 10, fVelocityXMax = 10; float fVelocityYMin = 0, fVelocityYMax = 0; float fVelocityZMin = 0, fVelocityZMax = 0; float fOverrideSpeed = 0; // 0 means don't override speed pNode->GetAttrValue( "VelocityXMin", fVelocityXMin ); pNode->GetAttrValue( "VelocityXMax", fVelocityXMax ); pNode->GetAttrValue( "VelocityYMin", fVelocityYMin ); pNode->GetAttrValue( "VelocityYMax", fVelocityYMax ); pNode->GetAttrValue( "VelocityZMin", fVelocityZMin ); pNode->GetAttrValue( "VelocityZMax", fVelocityZMax ); pNode->GetAttrValue( "OverrideSpeed", fOverrideSpeed ); int iNumParticles = 10; pNode->GetAttrValue( "NumParticles", iNumParticles ); pNode->GetAttrValue( "ParticlesBounce", m_bParticlesBounce ); pNode->GetAttrValue( "TilesStartX", m_fTilesStartX ); pNode->GetAttrValue( "TilesStartY", m_fTilesStartY ); pNode->GetAttrValue( "TilesSpacingX", m_fTilesSpacingX ); pNode->GetAttrValue( "TilesSpacingY", m_fTilesSpacingY ); pNode->GetAttrValue( "TileVelocityX", m_fTileVelocityX ); pNode->GetAttrValue( "TileVelocityY", m_fTileVelocityY ); switch( m_Type ) { case TYPE_SPRITE: { Actor* pActor = ActorUtil::LoadFromNode( pNode, this ); this->AddChild( pActor ); if( bStretch ) pActor->StretchTo( FullScreenRectF ); } break; case TYPE_PARTICLES: { RString sFile; ActorUtil::GetAttrPath( pNode, "File", sFile ); FixSlashesInPlace( sFile ); CollapsePath( sFile ); for( int i=0; i<iNumParticles; i++ ) { Actor* pActor = ActorUtil::MakeActor( sFile, this ); if( pActor == NULL ) continue; this->AddChild( pActor ); pActor->SetXY( randomf(float(FullScreenRectF.left),float(FullScreenRectF.right)), randomf(float(FullScreenRectF.top),float(FullScreenRectF.bottom)) ); pActor->SetZoom( randomf(fZoomMin,fZoomMax) ); m_vParticleVelocity.push_back( RageVector3( randomf(fVelocityXMin,fVelocityXMax), randomf(fVelocityYMin,fVelocityYMax), randomf(fVelocityZMin,fVelocityZMax) ) ); if( fOverrideSpeed != 0 ) { RageVec3Normalize( &m_vParticleVelocity[i], &m_vParticleVelocity[i] ); m_vParticleVelocity[i] *= fOverrideSpeed; } } } break; case TYPE_TILES: { RString sFile; ActorUtil::GetAttrPath( pNode, "File", sFile ); FixSlashesInPlace( sFile ); CollapsePath( sFile ); AutoActor s; s.Load( sFile ); if( m_fTilesSpacingX == -1 ) m_fTilesSpacingX = s->GetUnzoomedWidth(); if( m_fTilesSpacingY == -1 ) m_fTilesSpacingY = s->GetUnzoomedHeight(); m_iNumTilesWide = 2+(int)(SCREEN_WIDTH /m_fTilesSpacingX); m_iNumTilesHigh = 2+(int)(SCREEN_HEIGHT/m_fTilesSpacingY); unsigned NumSprites = m_iNumTilesWide * m_iNumTilesHigh; for( unsigned i=0; i<NumSprites; i++ ) { Actor* pSprite = ActorUtil::MakeActor( sFile, this ); if( pSprite == NULL ) continue; this->AddChild( pSprite ); pSprite->SetTextureWrapping( true ); // gets rid of some "cracks" pSprite->SetZoom( randomf(fZoomMin,fZoomMax) ); } } break; default: FAIL_M(ssprintf("Unrecognized layer type: %i", m_Type)); } bool bStartOnRandomFrame = false; pNode->GetAttrValue( "StartOnRandomFrame", bStartOnRandomFrame ); if( bStartOnRandomFrame ) { for( unsigned i=0; i<m_SubActors.size(); i++ ) m_SubActors[i]->SetState( RandomInt(m_SubActors[i]->GetNumStates()) ); } }