Files
itgmania212121/stepmania/src/NoteField.cpp
T

387 lines
12 KiB
C++
Raw Normal View History

2002-04-16 17:31:00 +00:00
#include "stdafx.h"
/*
-----------------------------------------------------------------------------
Class: NoteField
Desc: See header.
2002-05-19 01:59:48 +00:00
Copyright (c) 2001-2002 by the person(s) listed below. All rights reserved.
2002-04-16 17:31:00 +00:00
Chris Danford
-----------------------------------------------------------------------------
*/
#include "NoteField.h"
#include "RageUtil.h"
2002-05-01 19:14:55 +00:00
#include "GameConstantsAndTypes.h"
2002-07-23 01:41:40 +00:00
#include "PrefsManager.h"
2002-04-16 17:31:00 +00:00
#include "ArrowEffects.h"
#include "PrefsManager.h"
#include "GameManager.h"
2002-07-23 01:41:40 +00:00
#include "GameState.h"
2002-07-27 19:29:51 +00:00
#include "RageException.h"
#include "RageTimer.h"
2002-04-16 17:31:00 +00:00
2002-06-14 22:25:22 +00:00
const float HOLD_NOTE_BITS_PER_BEAT = 6;
const float HOLD_NOTE_BITS_PER_ROW = HOLD_NOTE_BITS_PER_BEAT / ELEMENTS_PER_BEAT;
const float ROWS_BETWEEN_HOLD_BITS = 1 / HOLD_NOTE_BITS_PER_ROW;
2002-04-16 17:31:00 +00:00
NoteField::NoteField()
{
m_rectMeasureBar.TurnShadowOff();
m_textMeasureNumber.Load( THEME->GetPathTo(FONT_NORMAL) );
m_textMeasureNumber.SetZoom( 1.0f );
m_rectMarkerBar.TurnShadowOff();
m_rectMarkerBar.SetEffectGlowing();
m_fBeginMarker = m_fEndMarker = -1;
2002-06-27 17:49:10 +00:00
2002-08-01 21:55:40 +00:00
m_fPercentFadeToFail = -1;
2002-04-16 17:31:00 +00:00
}
2002-07-28 20:28:37 +00:00
void NoteField::Load( NoteData* pNoteData, PlayerNumber pn, int iPixelsToDrawBehind, int iPixelsToDrawAhead )
2002-04-16 17:31:00 +00:00
{
2002-07-28 20:28:37 +00:00
m_PlayerNumber = pn;
2002-07-27 19:29:51 +00:00
m_iPixelsToDrawBehind = iPixelsToDrawBehind;
m_iPixelsToDrawAhead = iPixelsToDrawAhead;
2002-07-28 20:28:37 +00:00
2002-08-01 21:55:40 +00:00
m_fPercentFadeToFail = -1;
2002-08-01 03:15:27 +00:00
NoteDataWithScoring::Init();
for( int i=0; i<MAX_HOLD_NOTES; i++ )
m_bIsHoldingHoldNote[i] = false;
2002-07-28 20:28:37 +00:00
StyleDef* pStyleDef = GAMESTATE->GetCurrentStyleDef();
2002-04-16 17:31:00 +00:00
this->CopyAll( pNoteData );
// init arrow rotations and X positions
for( int c=0; c<m_iNumTracks; c++ )
{
2002-05-19 01:59:48 +00:00
CArray<D3DXCOLOR,D3DXCOLOR> arrayTweenColors;
2002-07-23 01:41:40 +00:00
GAMEMAN->GetTweenColors( c, arrayTweenColors );
2002-05-19 01:59:48 +00:00
2002-07-28 20:28:37 +00:00
m_ColorNote[c].Load( c, pn );
2002-04-16 17:31:00 +00:00
}
for( i=0; i<MAX_HOLD_NOTES; i++ )
2002-08-01 03:15:27 +00:00
m_fHoldNoteLife[i] = 1; // start with full life
2002-04-28 20:42:32 +00:00
2002-07-23 01:41:40 +00:00
ASSERT( m_iNumTracks == GAMESTATE->GetCurrentStyleDef()->m_iColsPerPlayer );
2002-04-16 17:31:00 +00:00
}
2002-07-28 20:28:37 +00:00
void NoteField::Update( float fDeltaTime )
2002-04-16 17:31:00 +00:00
{
m_rectMarkerBar.Update( fDeltaTime );
2002-08-01 21:55:40 +00:00
if( m_fPercentFadeToFail >= 0 )
m_fPercentFadeToFail = min( m_fPercentFadeToFail + fDeltaTime/3, 1 ); // take 3 seconds to totally fade
2002-04-16 17:31:00 +00:00
}
2002-04-28 20:42:32 +00:00
void NoteField::CreateTapNoteInstance( ColorNoteInstance &cni, const int iCol, const float fIndex, const D3DXCOLOR color )
2002-04-16 17:31:00 +00:00
{
2002-07-28 20:28:37 +00:00
const float fYOffset = ArrowGetYOffset( m_PlayerNumber, fIndex );
const float fYPos = ArrowGetYPos( m_PlayerNumber, fYOffset );
const float fRotation = ArrowGetRotation( m_PlayerNumber, iCol, fYOffset );
const float fXPos = ArrowGetXPos( m_PlayerNumber, iCol, fYOffset );
2002-08-01 21:55:40 +00:00
float fAlpha = ArrowGetAlpha( m_PlayerNumber, fYPos );
if( m_fPercentFadeToFail != -1 )
fAlpha = 1-m_fPercentFadeToFail;
2002-04-16 17:31:00 +00:00
2002-04-28 20:42:32 +00:00
D3DXCOLOR colorLeading, colorTrailing; // of the color part. Alpha here be overwritten with fAlpha!
if( color.a == -1 ) // indicated "NULL"
2002-07-28 20:28:37 +00:00
m_ColorNote[iCol].GetEdgeColorsFromIndexAndBeat( roundf(fIndex), colorLeading, colorTrailing );
2002-04-28 20:42:32 +00:00
else
colorLeading = colorTrailing = color;
2002-07-02 00:27:58 +00:00
float fAddAlpha = m_ColorNote[iCol].GetAddAlphaFromDiffuseAlpha( fAlpha );
2002-07-28 20:28:37 +00:00
int iGrayPartFrameNo = m_ColorNote[iCol].GetGrayPartFrameNoFromIndexAndBeat( roundf(fIndex), GAMESTATE->m_fSongBeat );
2002-04-16 17:31:00 +00:00
2002-04-28 20:42:32 +00:00
ColorNoteInstance instance = { fXPos, fYPos, fRotation, fAlpha, colorLeading, colorTrailing, fAddAlpha, iGrayPartFrameNo };
cni = instance;
2002-04-16 17:31:00 +00:00
}
2002-04-28 20:42:32 +00:00
void NoteField::CreateHoldNoteInstance( ColorNoteInstance &cni, const bool bActive, const float fIndex, const HoldNote &hn, const float fHoldNoteLife )
2002-04-16 17:31:00 +00:00
{
2002-04-28 20:42:32 +00:00
const int iCol = hn.m_iTrack;
2002-07-28 20:28:37 +00:00
const float fYOffset = ArrowGetYOffset( m_PlayerNumber, fIndex );
const float fYPos = ArrowGetYPos( m_PlayerNumber, fYOffset );
const float fRotation = ArrowGetRotation( m_PlayerNumber, iCol, fYOffset );
const float fXPos = ArrowGetXPos( m_PlayerNumber, iCol, fYOffset );
2002-08-01 21:55:40 +00:00
float fAlpha = ArrowGetAlpha( m_PlayerNumber, fYPos );
if( m_fPercentFadeToFail != -1 )
fAlpha = 1-m_fPercentFadeToFail;
2002-04-16 17:31:00 +00:00
2002-04-28 20:42:32 +00:00
int iGrayPartFrameNo;
2002-07-28 20:28:37 +00:00
if( bActive )
2002-04-28 20:42:32 +00:00
iGrayPartFrameNo = m_ColorNote[iCol].GetGrayPartFrameNoFull();
else
iGrayPartFrameNo = m_ColorNote[iCol].GetGrayPartFrameNoClear();
2002-04-16 17:31:00 +00:00
2002-04-28 20:42:32 +00:00
const float fPercentIntoHold = (fIndex-hn.m_iStartIndex)/(hn.m_iEndIndex-hn.m_iStartIndex);
D3DXCOLOR colorLeading( fPercentIntoHold, 1, 0, 1 ); // color shifts from green to yellow
colorLeading *= fHoldNoteLife;
colorLeading.a = 1;
D3DXCOLOR colorTrailing = colorLeading;
2002-07-02 00:27:58 +00:00
float fAddAlpha = m_ColorNote[iCol].GetAddAlphaFromDiffuseAlpha( fAlpha );
2002-04-16 17:31:00 +00:00
2002-04-28 20:42:32 +00:00
ColorNoteInstance instance = { fXPos, fYPos, fRotation, fAlpha, colorLeading, colorTrailing, fAddAlpha, iGrayPartFrameNo };
cni = instance;
2002-04-16 17:31:00 +00:00
}
void NoteField::DrawMeasureBar( const int iIndex, const int iMeasureNo )
{
2002-07-28 20:28:37 +00:00
const float fYOffset = ArrowGetYOffset( m_PlayerNumber, (float)iIndex );
const float fYPos = ArrowGetYPos( m_PlayerNumber, fYOffset );
2002-04-16 17:31:00 +00:00
m_rectMeasureBar.SetXY( 0, fYPos );
m_rectMeasureBar.SetWidth( (float)(m_iNumTracks+1) * ARROW_SIZE );
m_rectMeasureBar.SetHeight( 20 );
m_rectMeasureBar.SetDiffuseColor( D3DXCOLOR(0,0,0,0.5f) );
m_rectMeasureBar.Draw();
2002-06-29 11:59:09 +00:00
m_textMeasureNumber.SetDiffuseColor( D3DXCOLOR(1,1,1,1) );
m_textMeasureNumber.SetAddColor( D3DXCOLOR(1,1,1,0) );
2002-04-16 17:31:00 +00:00
m_textMeasureNumber.SetText( ssprintf("%d", iMeasureNo) );
m_textMeasureNumber.SetXY( -m_rectMeasureBar.GetZoomedWidth()/2 + 10, fYPos );
m_textMeasureNumber.Draw();
}
void NoteField::DrawMarkerBar( const int iIndex )
{
2002-07-28 20:28:37 +00:00
const float fYOffset = ArrowGetYOffset( m_PlayerNumber, (float)iIndex );
const float fYPos = ArrowGetYPos( m_PlayerNumber, fYOffset );
2002-04-16 17:31:00 +00:00
m_rectMarkerBar.SetXY( 0, fYPos );
m_rectMarkerBar.SetWidth( (float)(m_iNumTracks+1) * ARROW_SIZE );
m_rectMarkerBar.SetHeight( 20 );
m_rectMarkerBar.SetDiffuseColor( D3DXCOLOR(0,0,0,0.5f) );
m_rectMarkerBar.Draw();
}
2002-06-29 11:59:09 +00:00
void NoteField::DrawBPMText( const int iIndex, const float fBPM )
{
2002-07-28 20:28:37 +00:00
const float fYOffset = ArrowGetYOffset( m_PlayerNumber, (float)iIndex );
const float fYPos = ArrowGetYPos( m_PlayerNumber, fYOffset );
2002-06-29 11:59:09 +00:00
m_textMeasureNumber.SetDiffuseColor( D3DXCOLOR(1,0,0,1) );
m_textMeasureNumber.SetAddColor( D3DXCOLOR(1,1,1,cosf(TIMER->GetTimeSinceStart()*2)/2+0.5f) );
m_textMeasureNumber.SetText( ssprintf("%.2f", fBPM) );
2002-07-02 00:27:58 +00:00
m_textMeasureNumber.SetXY( -m_rectMeasureBar.GetZoomedWidth()/2 - 60, fYPos );
2002-06-29 11:59:09 +00:00
m_textMeasureNumber.Draw();
}
void NoteField::DrawFreezeText( const int iIndex, const float fSecs )
{
2002-07-28 20:28:37 +00:00
const float fYOffset = ArrowGetYOffset( m_PlayerNumber, (float)iIndex );
const float fYPos = ArrowGetYPos( m_PlayerNumber, fYOffset );
2002-06-29 11:59:09 +00:00
2002-07-02 00:27:58 +00:00
m_textMeasureNumber.SetDiffuseColor( D3DXCOLOR(0.8f,0.8f,0,1) );
2002-06-29 11:59:09 +00:00
m_textMeasureNumber.SetAddColor( D3DXCOLOR(1,1,1,cosf(TIMER->GetTimeSinceStart()*2)/2+0.5f) );
m_textMeasureNumber.SetText( ssprintf("%.2f", fSecs) );
2002-07-02 00:27:58 +00:00
m_textMeasureNumber.SetXY( -m_rectMeasureBar.GetZoomedWidth()/2 - 10, fYPos );
2002-06-29 11:59:09 +00:00
m_textMeasureNumber.Draw();
}
2002-05-19 01:59:48 +00:00
void NoteField::DrawPrimitives()
2002-04-16 17:31:00 +00:00
{
//LOG->Trace( "NoteField::DrawPrimitives()" );
2002-04-16 17:31:00 +00:00
2002-07-28 20:28:37 +00:00
float fSongBeat = max( 0, GAMESTATE->m_fSongBeat );
2002-04-16 17:31:00 +00:00
2002-07-28 20:28:37 +00:00
int iBaseFrameNo = (int)(fSongBeat*2.5) % NUM_FRAMES_IN_COLOR_ARROW_SPRITE; // 2.5 is a "fudge number" :-) This should be based on BPM
2002-04-16 17:31:00 +00:00
2002-07-28 20:28:37 +00:00
const float fBeatsToDrawBehind = m_iPixelsToDrawBehind * (1/(float)ARROW_SIZE) * (1/GAMESTATE->m_PlayerOptions[m_PlayerNumber].m_fArrowScrollSpeed);
const float fBeatsToDrawAhead = m_iPixelsToDrawAhead * (1/(float)ARROW_SIZE) * (1/GAMESTATE->m_PlayerOptions[m_PlayerNumber].m_fArrowScrollSpeed);
const int iIndexFirstArrowToDraw = max( 0, BeatToNoteRow( fSongBeat - fBeatsToDrawBehind ) );
const int iIndexLastArrowToDraw = BeatToNoteRow( fSongBeat + fBeatsToDrawAhead );
2002-04-16 17:31:00 +00:00
//LOG->Trace( "Drawing elements %d through %d", iIndexFirstArrowToDraw, iIndexLastArrowToDraw );
2002-04-16 17:31:00 +00:00
2002-07-28 20:28:37 +00:00
if( GAMESTATE->m_bEditing )
2002-04-16 17:31:00 +00:00
{
2002-06-29 11:59:09 +00:00
//
// Draw measure bars
//
2002-04-16 17:31:00 +00:00
for( int i=iIndexFirstArrowToDraw; i<=iIndexLastArrowToDraw; i++ )
{
if( i % ELEMENTS_PER_MEASURE == 0 )
2002-06-29 11:59:09 +00:00
DrawMeasureBar( i, i / ELEMENTS_PER_MEASURE + 1 );
2002-04-16 17:31:00 +00:00
}
2002-06-29 11:59:09 +00:00
//
// BPM text
//
2002-07-23 01:41:40 +00:00
CArray<BPMSegment,BPMSegment&> &aBPMSegments = GAMESTATE->m_pCurSong->m_BPMSegments;
2002-06-29 11:59:09 +00:00
for( i=0; i<aBPMSegments.GetSize(); i++ )
{
DrawBPMText( BeatToNoteRow(aBPMSegments[i].m_fStartBeat), aBPMSegments[i].m_fBPM );
}
//
// Freeze text
//
2002-07-23 01:41:40 +00:00
CArray<StopSegment,StopSegment&> &aStopSegments = GAMESTATE->m_pCurSong->m_StopSegments;
2002-07-11 19:02:26 +00:00
for( i=0; i<aStopSegments.GetSize(); i++ )
2002-06-29 11:59:09 +00:00
{
2002-07-11 19:02:26 +00:00
DrawFreezeText( BeatToNoteRow(aStopSegments[i].m_fStartBeat), aStopSegments[i].m_fStopSeconds );
2002-06-29 11:59:09 +00:00
}
//
// Draw marker bars
//
2002-04-16 17:31:00 +00:00
if( m_fBeginMarker != -1 )
{
2002-05-19 01:59:48 +00:00
DrawMarkerBar( BeatToNoteRow(m_fBeginMarker) );
2002-04-16 17:31:00 +00:00
}
if( m_fEndMarker != -1 )
{
2002-05-19 01:59:48 +00:00
DrawMarkerBar( BeatToNoteRow(m_fEndMarker) );
2002-04-16 17:31:00 +00:00
}
2002-06-29 11:59:09 +00:00
2002-04-16 17:31:00 +00:00
}
2002-06-29 11:59:09 +00:00
2002-04-16 17:31:00 +00:00
//
2002-04-28 20:42:32 +00:00
// Optimization is very important here because there are so many arrows to draw. We're going
// to draw the arrows in order of column. This will let us fill up a vertex buffer of arrows
// so we can draw them in one swoop without texture or state changes.
2002-04-16 17:31:00 +00:00
//
2002-04-28 20:42:32 +00:00
for( int c=0; c<m_iNumTracks; c++ ) // for each arrow column
{
const int MAX_COLOR_NOTE_INSTANCES = 300;
ColorNoteInstance instances[MAX_COLOR_NOTE_INSTANCES];
2002-06-14 22:25:22 +00:00
int iCount = 0; // number of valid elements in the instances array
2002-04-28 20:42:32 +00:00
2002-04-16 17:31:00 +00:00
2002-06-14 22:25:22 +00:00
/////////////////////////////////
// Draw all HoldNotes in this column (so that they appear under the tap notes)
/////////////////////////////////
for( int i=0; i<m_iNumHoldNotes; i++ )
2002-04-16 17:31:00 +00:00
{
2002-04-28 20:42:32 +00:00
HoldNote &hn = m_HoldNotes[i];
2002-08-01 03:15:27 +00:00
HoldNoteScore &hns = m_HoldNoteScores[i];
if( hns == HNS_OK ) // if this HoldNote was completed
continue; // don't draw anything
const float fLife = m_fHoldNoteLife[i];
2002-04-16 17:31:00 +00:00
2002-04-28 20:42:32 +00:00
if( hn.m_iTrack != c ) // this HoldNote doesn't belong to this column
continue;
2002-04-16 17:31:00 +00:00
2002-04-28 20:42:32 +00:00
// If no part of this HoldNote is on the screen, skip it
if( !( iIndexFirstArrowToDraw <= hn.m_iEndIndex && hn.m_iEndIndex <= iIndexLastArrowToDraw ||
iIndexFirstArrowToDraw <= hn.m_iStartIndex && hn.m_iStartIndex <= iIndexLastArrowToDraw ||
hn.m_iStartIndex < iIndexFirstArrowToDraw && hn.m_iEndIndex > iIndexLastArrowToDraw ) )
{
2002-06-14 22:25:22 +00:00
continue; // skip
2002-04-28 20:42:32 +00:00
}
2002-04-16 17:31:00 +00:00
2002-06-14 22:25:22 +00:00
// If this note was in the past and has life > 0, then it was completed and don't draw it!
2002-08-01 03:15:27 +00:00
if( hn.m_iEndIndex < BeatToNoteRow(fSongBeat) && fLife > 0 && m_bIsHoldingHoldNote[i] )
2002-06-14 22:25:22 +00:00
continue; // skip
2002-04-28 20:42:32 +00:00
const int iCol = hn.m_iTrack;
2002-08-01 03:15:27 +00:00
const float fHoldNoteLife = m_fHoldNoteLife[i];
const bool bActive = m_bIsHoldingHoldNote[i]; // hack: added -1 because hn.m_iStartIndex changes as note is held
2002-04-16 17:31:00 +00:00
2002-06-14 22:25:22 +00:00
// parts of the hold
2002-07-28 20:28:37 +00:00
const float fStartDrawingAtBeat = froundf( (float)hn.m_iStartIndex, ROWS_BETWEEN_HOLD_BITS/GAMESTATE->m_PlayerOptions[m_PlayerNumber].m_fArrowScrollSpeed );
2002-06-14 22:25:22 +00:00
for( float j=fStartDrawingAtBeat;
j<=hn.m_iEndIndex;
2002-07-28 20:28:37 +00:00
j+=ROWS_BETWEEN_HOLD_BITS/GAMESTATE->m_PlayerOptions[m_PlayerNumber].m_fArrowScrollSpeed ) // for each bit of the hold
2002-04-28 20:42:32 +00:00
{
// check if this arrow is off the the screen
if( j < iIndexFirstArrowToDraw || iIndexLastArrowToDraw < j)
continue; // skip this arrow
2002-04-16 17:31:00 +00:00
2002-08-01 03:15:27 +00:00
if( bActive && NoteRowToBeat(j) < fSongBeat )
2002-07-11 19:02:26 +00:00
continue;
2002-06-14 22:25:22 +00:00
CreateHoldNoteInstance( instances[iCount++], bActive, (float)j, hn, fHoldNoteLife );
2002-04-28 20:42:32 +00:00
}
2002-04-16 17:31:00 +00:00
}
2002-07-28 20:28:37 +00:00
const bool bDrawAddPass = GAMESTATE->m_PlayerOptions[m_PlayerNumber].m_AppearanceType != PlayerOptions::APPEARANCE_VISIBLE;
2002-04-28 20:42:32 +00:00
if( iCount > 0 )
m_ColorNote[c].DrawList( iCount, instances, bDrawAddPass );
2002-06-14 22:25:22 +00:00
iCount = 0; // reset count
///////////////////////////////////
// Draw all TapNotes in this column
///////////////////////////////////
for( i=iIndexFirstArrowToDraw; i<=iIndexLastArrowToDraw; i++ ) // for each row
{
if( m_TapNotes[c][i] == '0' )
continue; // no note here
// See if there is a hold step that begins on this beat.
bool bHoldNoteOnThisBeat = false;
2002-08-01 03:15:27 +00:00
float fHoldLife = -1;
2002-06-14 22:25:22 +00:00
for( int j=0; j<m_iNumHoldNotes; j++ )
{
if( m_HoldNotes[j].m_iStartIndex == i )
{
bHoldNoteOnThisBeat = true;
2002-08-01 03:15:27 +00:00
fHoldLife = m_fHoldNoteLife[j];
2002-06-14 22:25:22 +00:00
break;
}
}
if( bHoldNoteOnThisBeat )
2002-08-01 03:15:27 +00:00
{
D3DXCOLOR color(0,1,0,1);
color.r *= fHoldLife;
color.g *= fHoldLife;
color.b *= fHoldLife;
CreateTapNoteInstance( instances[iCount++], c, (float)i, color );
}
2002-06-14 22:25:22 +00:00
else
CreateTapNoteInstance( instances[iCount++], c, (float)i );
}
if( iCount > 0 )
m_ColorNote[c].DrawList( iCount, instances, bDrawAddPass );
2002-04-16 17:31:00 +00:00
}
2002-04-28 20:42:32 +00:00
2002-04-16 17:31:00 +00:00
}
void NoteField::RemoveTapNoteRow( int iIndex )
{
for( int c=0; c<m_iNumTracks; c++ )
m_TapNotes[c][iIndex] = '0';
}
2002-08-01 21:55:40 +00:00
void NoteField::FadeToFail()
{
m_fPercentFadeToFail = max( 0.0f, m_fPercentFadeToFail ); // this will slowly increase every Update()
// don't fade all over again if this is called twice
}