rewrite of BitmapText (still needs work) and support for BPM changes.
This commit is contained in:
@@ -10,75 +10,81 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "BitmapText.h"
|
#include "BitmapText.h"
|
||||||
#include <assert.h>
|
|
||||||
#include "IniFile.h"
|
#include "IniFile.h"
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
BitmapText::BitmapText()
|
BitmapText::BitmapText()
|
||||||
{
|
{
|
||||||
m_pFont = NULL;
|
// m_colorTop = D3DXCOLOR(1,1,1,1);
|
||||||
m_colorTop = D3DXCOLOR(1,1,1,1);
|
// m_colorBottom = D3DXCOLOR(1,1,1,1);
|
||||||
m_colorBottom = D3DXCOLOR(1,1,1,1);
|
|
||||||
|
|
||||||
}
|
for( int i=0; i<NUM_CHARS; i++ )
|
||||||
|
m_fCharWidthsInSourcePixels[i] = 16;
|
||||||
BitmapText::~BitmapText()
|
|
||||||
{
|
|
||||||
delete m_pFont;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool BitmapText::LoadFromFontName( CString sFontName )
|
bool BitmapText::LoadFromFontName( CString sFontName )
|
||||||
{
|
{
|
||||||
RageLog( "BitmapText::LoadFromFontName(%s)", sFontName );
|
RageLog( "BitmapText::LoadFromFontName(%s)", sFontName );
|
||||||
|
|
||||||
SAFE_DELETE( m_pFont ); // delete old font (if any)
|
|
||||||
|
|
||||||
m_sFontName = sFontName; // save font name
|
m_sFontName = sFontName; // save font name
|
||||||
|
|
||||||
m_pFont= new CBitmapFont( SCREEN->GetD3D(), SCREEN->GetDevice() );
|
Sprite::LoadFromTexture( ssprintf("Fonts/%s 16x16.png",sFontName) );
|
||||||
m_pFont->Load( BL_BITMAP, ssprintf("Fonts/%s.png",sFontName) );
|
LoadCharWidths( ssprintf("Fonts/%s.widths",sFontName) );
|
||||||
m_pFont->Load( BL_SIZES, ssprintf("Fonts/%s.dat",sFontName) );
|
|
||||||
|
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
void BitmapText::Draw()
|
// returns the font height in the case of a bitmap load. note does not use the real bitmap height but rather
|
||||||
|
// the height of the bitmap / 16. generally returns > 0 for success.
|
||||||
|
bool BitmapText::LoadCharWidths( CString sWidthFilePath )
|
||||||
{
|
{
|
||||||
RECT rect = m_pFont->GetTextRect(m_sText, 0, 0);
|
FILE *file;
|
||||||
float text_width = RECTWIDTH( rect );
|
file = fopen( sWidthFilePath, "rb" );
|
||||||
float text_height = RECTHEIGHT( rect );
|
for( int i=0; i<256; i++ ) {
|
||||||
|
BYTE widthSourcePixels;
|
||||||
|
if( fread(&widthSourcePixels, 1, 1, file) != 1 )
|
||||||
LPDIRECT3DDEVICE8 pd3dDevice = SCREEN->GetDevice();
|
return false;
|
||||||
|
m_fCharWidthsInSourcePixels[i] = widthSourcePixels;
|
||||||
// calculate transforms
|
}
|
||||||
D3DXMATRIX matWorld, matTemp;
|
fclose(file);
|
||||||
D3DXMatrixIdentity( &matWorld ); // initialize world
|
return true;
|
||||||
//D3DXMatrixScaling( &matTemp, m_size.x, m_size.y, 1 ); // scale to the native height and width
|
|
||||||
//matWorld *= matTemp;
|
|
||||||
D3DXMatrixScaling( &matTemp, m_scale.x, m_scale.y, 1 ); // add in the zoom
|
|
||||||
matWorld *= matTemp;
|
|
||||||
D3DXMatrixRotationYawPitchRoll( &matTemp, m_rotation.y, m_rotation.x, m_rotation.z ); // add in the rotation
|
|
||||||
matWorld *= matTemp;
|
|
||||||
D3DXMatrixTranslation( &matTemp, m_pos.x, m_pos.y, 0 ); // add in the translation
|
|
||||||
matWorld *= matTemp;
|
|
||||||
pd3dDevice->SetTransform( D3DTS_WORLD, &matWorld );
|
|
||||||
|
|
||||||
D3DXMATRIX matView;
|
|
||||||
D3DXMatrixIdentity( &matView );
|
|
||||||
pd3dDevice->SetTransform( D3DTS_VIEW, &matView );
|
|
||||||
|
|
||||||
D3DXMATRIX matProj;
|
|
||||||
D3DXMatrixOrthoOffCenterLH( &matProj, 0, 640, 480, 0, -100, 100 );
|
|
||||||
pd3dDevice->SetTransform( D3DTS_PROJECTION, &matProj );
|
|
||||||
|
|
||||||
m_pFont->BeginDraw();
|
|
||||||
m_pFont->DrawTextEx(m_sText, -text_width/2, -text_height/2, m_colorTop, m_colorBottom, 1.0f);
|
|
||||||
//m_pFont->DrawTextEx("Cool Effects!", 50, 80, 0xffffff00, 0xffff0000, 2.0f);
|
|
||||||
//m_pFont->DrawTextEx("Cool Effects!", 50, 120, 0x1100ffff, 0x8800ffff, 2.0f);
|
|
||||||
m_pFont->EndDraw();
|
|
||||||
///////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// get a rectangle for the text, considering a possible text scaling.
|
||||||
|
// useful to know if some text is visible or not
|
||||||
|
float BitmapText::GetTextWidthInSourcePixels()
|
||||||
|
{
|
||||||
|
float fTextWidth = 0;
|
||||||
|
|
||||||
|
for( int i=0; i<m_sText.GetLength(); i++ )
|
||||||
|
fTextWidth += m_fCharWidthsInSourcePixels[ m_sText[i] ];
|
||||||
|
|
||||||
|
return fTextWidth;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// draw text at x, y using colorTop blended down to colorBottom, with size multiplied by scale
|
||||||
|
void BitmapText::Draw()
|
||||||
|
{
|
||||||
|
float fCenterX = GetX();
|
||||||
|
float fTextWidthInSourcePixels = GetTextWidthInSourcePixels();
|
||||||
|
float fTextWidth = fTextWidthInSourcePixels* GetZoom();
|
||||||
|
float fFrameWidth = GetZoomedWidth();
|
||||||
|
float fX = fCenterX - (fTextWidth/2);
|
||||||
|
|
||||||
|
|
||||||
|
for( int i=0; i<m_sText.GetLength(); i++ ) {
|
||||||
|
char c = m_sText[i];
|
||||||
|
SetState( c );
|
||||||
|
SetX( fX ); // set X acording to offset
|
||||||
|
Sprite::Draw();
|
||||||
|
fX += m_fCharWidthsInSourcePixels[c] * GetZoom();
|
||||||
|
}
|
||||||
|
|
||||||
|
// set properties back to original
|
||||||
|
SetX( fCenterX );
|
||||||
|
}
|
||||||
|
|||||||
+19
-12
@@ -12,36 +12,43 @@
|
|||||||
#define _BITMAPTEXT_H_
|
#define _BITMAPTEXT_H_
|
||||||
|
|
||||||
|
|
||||||
//#include "Actor.h"
|
|
||||||
#include "Sprite.h"
|
#include "Sprite.h"
|
||||||
#include "BitmapText.h"
|
#include "BitmapText.h"
|
||||||
|
|
||||||
#include "BitmapFont.h"
|
|
||||||
|
const int NUM_CHARS = 256;
|
||||||
|
|
||||||
|
|
||||||
|
class BitmapText : public Sprite
|
||||||
class BitmapText : public Actor
|
|
||||||
{
|
{
|
||||||
|
protected:
|
||||||
|
|
||||||
public:
|
public:
|
||||||
BitmapText();
|
BitmapText();
|
||||||
~BitmapText();
|
|
||||||
|
|
||||||
bool LoadFromFontName( CString sFontName );
|
bool LoadFromFontName( CString sFontName );
|
||||||
void SetText( CString sText ) { m_sText = sText; };
|
void SetText( CString sText ) { m_sText = sText; };
|
||||||
CString GetText() { return m_sText; };
|
CString GetText() { return m_sText; };
|
||||||
|
|
||||||
void SetTopColor( D3DXCOLOR new_color ) { m_colorTop = new_color; };
|
bool LoadFontWidths( CString sFilePath );
|
||||||
void SetBottomColor( D3DXCOLOR new_color ) { m_colorBottom = new_color; };
|
//float GetWidthZoomed();
|
||||||
void SetColor( D3DXCOLOR new_color ) { SetTopColor(new_color); SetBottomColor(new_color); };
|
|
||||||
|
|
||||||
virtual void Draw();
|
// void SetTopColor( D3DXCOLOR new_color ) { m_colorTop = new_color; };
|
||||||
|
// void SetBottomColor( D3DXCOLOR new_color ) { m_colorBottom = new_color; };
|
||||||
|
// void SetColor( D3DXCOLOR new_color ) { SetTopColor(new_color); SetBottomColor(new_color); };
|
||||||
|
|
||||||
|
void Draw();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
bool LoadCharWidths( CString sWidthFilePath );
|
||||||
|
float GetTextWidthInSourcePixels(); // in logical, pre-scaled units
|
||||||
|
|
||||||
CString m_sFontName;
|
CString m_sFontName;
|
||||||
CBitmapFont* m_pFont;
|
float m_fCharWidthsInSourcePixels[NUM_CHARS]; // in soure coordinate space
|
||||||
|
|
||||||
CString m_sText; // the string that the font is displaying
|
CString m_sText; // the string that the font is displaying
|
||||||
D3DXCOLOR m_colorTop;
|
// D3DXCOLOR m_colorTop;
|
||||||
D3DXCOLOR m_colorBottom;
|
// D3DXCOLOR m_colorBottom;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -68,7 +68,7 @@ void RageBitmapTexture::Create()
|
|||||||
D3DX_DEFAULT, D3DX_DEFAULT, // width, height
|
D3DX_DEFAULT, D3DX_DEFAULT, // width, height
|
||||||
D3DX_DEFAULT, // mip map levels
|
D3DX_DEFAULT, // mip map levels
|
||||||
0, // usage (is a render target?)
|
0, // usage (is a render target?)
|
||||||
D3DFMT_A4R4G4B4, // our preferred texture format
|
D3DFMT_UNKNOWN, // our preferred texture format
|
||||||
D3DPOOL_MANAGED, // which memory pool
|
D3DPOOL_MANAGED, // which memory pool
|
||||||
D3DX_DEFAULT, // filter
|
D3DX_DEFAULT, // filter
|
||||||
D3DX_DEFAULT, // mip filter
|
D3DX_DEFAULT, // mip filter
|
||||||
|
|||||||
+59
-12
@@ -25,8 +25,9 @@
|
|||||||
//////////////////////////////
|
//////////////////////////////
|
||||||
Song::Song()
|
Song::Song()
|
||||||
{
|
{
|
||||||
m_fBPM = 0;
|
m_bChangedSinceSave = false;
|
||||||
m_fBeatOffset = 0;
|
// m_fBPM = 0;
|
||||||
|
m_fOffsetInSeconds = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Song::LoadFromSongDir( CString sDir )
|
bool Song::LoadFromSongDir( CString sDir )
|
||||||
@@ -120,8 +121,17 @@ bool Song::LoadSongInfoFromBMSFile( CString sPath )
|
|||||||
}
|
}
|
||||||
else if( value_name == "#ARTIST" )
|
else if( value_name == "#ARTIST" )
|
||||||
m_sArtist = data_array[0];
|
m_sArtist = data_array[0];
|
||||||
else if( value_name == "#BPM" )
|
else if( value_name == "#BPM" ) {
|
||||||
m_fBPM = (FLOAT)atof( data_array[0] );
|
BPMSegment new_seg;
|
||||||
|
new_seg.m_iStartBeat = 0;
|
||||||
|
new_seg.m_fBPM = (float)atof( data_array[0] );
|
||||||
|
// find insertion point
|
||||||
|
for( int i=0; i<m_BPMSegments.GetSize(); i++ )
|
||||||
|
if( m_BPMSegments[i].m_iStartBeat > new_seg.m_iStartBeat )
|
||||||
|
break;
|
||||||
|
m_BPMSegments.InsertAt( i, new_seg );
|
||||||
|
RageLog( "Inserting new BPM change at beat %d, BPM %f, index %d", new_seg.m_iStartBeat, new_seg.m_fBPM, i );
|
||||||
|
}
|
||||||
else if( value_name == "#BackBMP" || value_name == "#backBMP")
|
else if( value_name == "#BackBMP" || value_name == "#backBMP")
|
||||||
m_sBackground = data_array[0];
|
m_sBackground = data_array[0];
|
||||||
else if( value_name == "#WAV99" )
|
else if( value_name == "#WAV99" )
|
||||||
@@ -129,7 +139,29 @@ bool Song::LoadSongInfoFromBMSFile( CString sPath )
|
|||||||
else if( value_name.GetLength() == 6 ) // this is probably step or offset data. Looks like "#00705"
|
else if( value_name.GetLength() == 6 ) // this is probably step or offset data. Looks like "#00705"
|
||||||
{
|
{
|
||||||
int iMeasureNo = atoi( value_name.Mid(1,3) );
|
int iMeasureNo = atoi( value_name.Mid(1,3) );
|
||||||
int iNoteNum = atoi( value_name.Mid(4,2) );
|
int iTrackNum = atoi( value_name.Mid(4,2) );
|
||||||
|
|
||||||
|
if( m_sTitle.Find("era") > 0 )
|
||||||
|
m_sTitle = m_sTitle;
|
||||||
|
switch( iTrackNum )
|
||||||
|
{
|
||||||
|
case 03: // bpm
|
||||||
|
{
|
||||||
|
int iNewBPM;
|
||||||
|
sscanf( data_array[0], "%x", &iNewBPM ); // data is in hexadecimal
|
||||||
|
BPMSegment new_seg;
|
||||||
|
new_seg.m_iStartBeat = iMeasureNo * 4;
|
||||||
|
new_seg.m_fBPM = (float)iNewBPM;
|
||||||
|
// find insertion point
|
||||||
|
for( int i=0; i<m_BPMSegments.GetSize(); i++ )
|
||||||
|
if( m_BPMSegments[i].m_iStartBeat > new_seg.m_iStartBeat )
|
||||||
|
break;
|
||||||
|
m_BPMSegments.InsertAt( i, new_seg );
|
||||||
|
RageLog( "Inserting new BPM change at beat %d, BPM %f, index %d", new_seg.m_iStartBeat, new_seg.m_fBPM, i );
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
CString sNoteData = data_array[0];
|
CString sNoteData = data_array[0];
|
||||||
CArray<BOOL, BOOL&> arrayNotes;
|
CArray<BOOL, BOOL&> arrayNotes;
|
||||||
|
|
||||||
@@ -141,23 +173,38 @@ bool Song::LoadSongInfoFromBMSFile( CString sPath )
|
|||||||
}
|
}
|
||||||
|
|
||||||
const int iNumNotesInThisMeasure = arrayNotes.GetSize();
|
const int iNumNotesInThisMeasure = arrayNotes.GetSize();
|
||||||
//RageLog( "%s:%s: iMeasureNo = %d, iNoteNum = %d, iNumNotesInThisMeasure = %d",
|
//RageLog( "%s:%s: iMeasureNo = %d, iTrackNum = %d, iNumNotesInThisMeasure = %d",
|
||||||
// valuename, sNoteData, iMeasureNo, iNoteNum, iNumNotesInThisMeasure );
|
// valuename, sNoteData, iMeasureNo, iTrackNum, iNumNotesInThisMeasure );
|
||||||
for( int j=0; j<iNumNotesInThisMeasure; j++ )
|
for( int j=0; j<iNumNotesInThisMeasure; j++ )
|
||||||
{
|
{
|
||||||
if( arrayNotes.GetAt(j) == TRUE )
|
if( arrayNotes.GetAt(j) == TRUE )
|
||||||
{
|
{
|
||||||
FLOAT fPercentThroughMeasure = (FLOAT)j/(FLOAT)iNumNotesInThisMeasure;
|
float fPercentThroughMeasure = (float)j/(float)iNumNotesInThisMeasure;
|
||||||
|
|
||||||
// index is in quarter beats starting at beat 0
|
// index is in quarter beats starting at beat 0
|
||||||
int iStepIndex = (int) ( (iMeasureNo + fPercentThroughMeasure)
|
int iStepIndex = (int) ( (iMeasureNo + fPercentThroughMeasure)
|
||||||
* BEATS_PER_MEASURE * ELEMENTS_PER_BEAT );
|
* BEATS_PER_MEASURE * ELEMENTS_PER_BEAT );
|
||||||
|
|
||||||
switch( iNoteNum )
|
switch( iTrackNum )
|
||||||
{
|
{
|
||||||
case 01: // offset
|
case 01: // offset
|
||||||
m_fBeatOffset = StepIndexToBeat(iStepIndex);
|
{
|
||||||
|
float fBeatOffset = StepIndexToBeat(iStepIndex);
|
||||||
|
float fBPS = m_BPMSegments[0].m_fBPM/60.0f;
|
||||||
|
m_fOffsetInSeconds = fBeatOffset / fBPS;
|
||||||
//RageLog( "Found offset to be index %d, beat %f", iStepIndex, StepIndexToBeat(iStepIndex) );
|
//RageLog( "Found offset to be index %d, beat %f", iStepIndex, StepIndexToBeat(iStepIndex) );
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 03: // bpm
|
||||||
|
{
|
||||||
|
int iNewBPM;
|
||||||
|
sscanf( data_array[0], "%x", &iNewBPM ); // data is in hexadecimal
|
||||||
|
BPMSegment seg;
|
||||||
|
seg.m_iStartBeat = iMeasureNo * 4;
|
||||||
|
seg.m_fBPM = (float)iNewBPM;
|
||||||
|
m_BPMSegments.Add(seg);
|
||||||
|
RageLog( "Found new BPM change at beat %d, BPM %f", seg.m_iStartBeat, seg.m_fBPM );
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -286,10 +333,10 @@ void Song::TidyUpData()
|
|||||||
if( m_sTitle == "" ) m_sTitle = "Untitled song";
|
if( m_sTitle == "" ) m_sTitle = "Untitled song";
|
||||||
if( m_sArtist == "" ) m_sArtist = "Unknown artist";
|
if( m_sArtist == "" ) m_sArtist = "Unknown artist";
|
||||||
if( m_sCreator == "" ) m_sCreator = "";
|
if( m_sCreator == "" ) m_sCreator = "";
|
||||||
if( m_fBPM == 0 )
|
if( m_BPMSegments.GetSize() == 0 )
|
||||||
RageError( ssprintf("No #BPM specified in '%s.'", GetSongFilePath()) );
|
RageError( ssprintf("No #BPM specified in '%s.'", GetSongFilePath()) );
|
||||||
|
|
||||||
if( m_fBeatOffset == 0.0 )
|
if( m_fOffsetInSeconds == 0.0 )
|
||||||
RageLog( "WARNING: #OFFSET or #GAP in '%s' is either 0.0, or was missing.", GetSongFilePath() );
|
RageLog( "WARNING: #OFFSET or #GAP in '%s' is either 0.0, or was missing.", GetSongFilePath() );
|
||||||
|
|
||||||
if( m_sMusic == "" || !DoesFileExist(GetMusicPath()) )
|
if( m_sMusic == "" || !DoesFileExist(GetMusicPath()) )
|
||||||
|
|||||||
@@ -23,7 +23,7 @@
|
|||||||
#include "GameInfo.h"
|
#include "GameInfo.h"
|
||||||
#include "WindowManager.h"
|
#include "WindowManager.h"
|
||||||
|
|
||||||
#include "WindowIntroCovers.h"
|
#include "WindowTitleMenu.h"
|
||||||
#include "WindowSandbox.h"
|
#include "WindowSandbox.h"
|
||||||
|
|
||||||
#include <DXUtil.h>
|
#include <DXUtil.h>
|
||||||
@@ -287,6 +287,11 @@ LRESULT CALLBACK WndProc( HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam )
|
|||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
HRESULT CreateObjects( HWND hWnd )
|
HRESULT CreateObjects( HWND hWnd )
|
||||||
{
|
{
|
||||||
|
|
||||||
|
srand( (unsigned)time(NULL) ); // seed number generator
|
||||||
|
|
||||||
|
RageLogStart();
|
||||||
|
|
||||||
SCREEN = new RageScreen( hWnd );
|
SCREEN = new RageScreen( hWnd );
|
||||||
TM = new RageTextureManager( SCREEN );
|
TM = new RageTextureManager( SCREEN );
|
||||||
SOUND = new RageSound( hWnd );
|
SOUND = new RageSound( hWnd );
|
||||||
@@ -296,15 +301,12 @@ HRESULT CreateObjects( HWND hWnd )
|
|||||||
GAMEINFO = new GameInfo;
|
GAMEINFO = new GameInfo;
|
||||||
WM = new WindowManager;
|
WM = new WindowManager;
|
||||||
|
|
||||||
RageLogStart();
|
|
||||||
|
DXUtil_Timer( TIMER_START ); // Start the accurate timer
|
||||||
|
|
||||||
//WM->SetNewWindow( new WindowSandbox );
|
//WM->SetNewWindow( new WindowSandbox );
|
||||||
WM->SetNewWindow( new WindowIntroCovers );
|
WM->SetNewWindow( new WindowTitleMenu );
|
||||||
|
|
||||||
srand( (unsigned)time(NULL) );
|
|
||||||
|
|
||||||
// Start the accurate timer
|
|
||||||
DXUtil_Timer( TIMER_START );
|
|
||||||
|
|
||||||
return S_OK;
|
return S_OK;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -284,14 +284,6 @@ SOURCE=.\Banner.h
|
|||||||
# End Source File
|
# End Source File
|
||||||
# Begin Source File
|
# Begin Source File
|
||||||
|
|
||||||
SOURCE=.\BitmapFont.cpp
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=.\BitmapFont.h
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=.\BitmapText.cpp
|
SOURCE=.\BitmapText.cpp
|
||||||
# End Source File
|
# End Source File
|
||||||
# Begin Source File
|
# Begin Source File
|
||||||
|
|||||||
+41
-5
@@ -48,9 +48,41 @@ public:
|
|||||||
CString GetTitle() {return m_sTitle; };
|
CString GetTitle() {return m_sTitle; };
|
||||||
CString GetArtist() {return m_sArtist; };
|
CString GetArtist() {return m_sArtist; };
|
||||||
CString GetCreator() {return m_sCreator; };
|
CString GetCreator() {return m_sCreator; };
|
||||||
float GetBeatOffset() {return m_fBeatOffset; };
|
// float GetBeatOffset() {return m_fBeatOffset; };
|
||||||
float GetBPM() {return m_fBPM; };
|
void GetMinMaxBPM( int &iMinBPM, int &iMaxBPM )
|
||||||
float GetBeatsPerSecond() {return m_fBPM / 60.0f; };
|
{
|
||||||
|
iMaxBPM = 0;
|
||||||
|
iMinBPM = 100000; // inf
|
||||||
|
for( int i=0; i<m_BPMSegments.GetSize(); i++ ) {
|
||||||
|
if( m_BPMSegments[i].m_fBPM > iMaxBPM )
|
||||||
|
iMaxBPM = (int)m_BPMSegments[i].m_fBPM;
|
||||||
|
if( m_BPMSegments[i].m_fBPM < iMinBPM )
|
||||||
|
iMinBPM = (int)m_BPMSegments[i].m_fBPM;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
void GetBeatAndBPSFromElapsedTime( float fElapsedTime, float &fBeatOut, float &fBPSOut )
|
||||||
|
{
|
||||||
|
if( fElapsedTime > 50 )
|
||||||
|
fElapsedTime = fElapsedTime;
|
||||||
|
fElapsedTime += m_fOffsetInSeconds;
|
||||||
|
|
||||||
|
for( int i=0; i<m_BPMSegments.GetSize(); i++ ) {
|
||||||
|
int iStartBeatThisSegment = m_BPMSegments[i].m_iStartBeat;
|
||||||
|
bool bIsLastBPMSegment = i==m_BPMSegments.GetSize()-1;
|
||||||
|
int iStartBeatNextSegment = bIsLastBPMSegment ? 40000/*inf*/ : m_BPMSegments[i+1].m_iStartBeat;
|
||||||
|
int iBeatsInThisSegment = iStartBeatNextSegment - iStartBeatThisSegment;
|
||||||
|
float fBPM = m_BPMSegments[i].m_fBPM;
|
||||||
|
float fBPS = fBPM / 60.0f;
|
||||||
|
float fSecondsInThisSegment = iBeatsInThisSegment / fBPS;
|
||||||
|
if( fElapsedTime > fSecondsInThisSegment )
|
||||||
|
fElapsedTime -= fSecondsInThisSegment;
|
||||||
|
else {
|
||||||
|
fBeatOut = iStartBeatThisSegment + fElapsedTime*fBPS;
|
||||||
|
fBPSOut = fBPS;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
@@ -59,16 +91,20 @@ private:
|
|||||||
CString m_sSongFile;
|
CString m_sSongFile;
|
||||||
CString m_sSongDir;
|
CString m_sSongDir;
|
||||||
|
|
||||||
|
bool m_bChangedSinceSave;
|
||||||
CString m_sTitle;
|
CString m_sTitle;
|
||||||
CString m_sArtist;
|
CString m_sArtist;
|
||||||
CString m_sCreator;
|
CString m_sCreator;
|
||||||
float m_fBPM;
|
// float m_fBPM;
|
||||||
float m_fBeatOffset;
|
float m_fOffsetInSeconds;
|
||||||
|
|
||||||
CString m_sMusic;
|
CString m_sMusic;
|
||||||
CString m_sBanner;
|
CString m_sBanner;
|
||||||
CString m_sBackground;
|
CString m_sBackground;
|
||||||
|
|
||||||
|
struct BPMSegment{ int m_iStartBeat; float m_fBPM; };
|
||||||
|
CArray<BPMSegment, BPMSegment&> m_BPMSegments;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
CArray<Steps, Steps&> arraySteps;
|
CArray<Steps, Steps&> arraySteps;
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user