diff --git a/Output/Graphics/Logo.png b/Output/Graphics/Logo.png index 2ad40d2f..0977ea93 100644 Binary files a/Output/Graphics/Logo.png and b/Output/Graphics/Logo.png differ diff --git a/Output/Readme.txt b/Output/Readme.txt new file mode 100644 index 00000000..4f05511a --- /dev/null +++ b/Output/Readme.txt @@ -0,0 +1,126 @@ +Vocaluxe 0.1 README +---------------------------- + +================================= += 1. About = += 2. Release Notes = += 3. Command-Line Parameters = += 4. Controls = += 5. Help & Support = += 6. Source Code = +================================= + + +================================= += 1. About = +================================= + +Vocaluxe is a free and open source singing game. It allows up to three players (currently) to sing +along with music using microphones in order to score points, depending on the pitch of the voice +and the rhythm of singing. + +Vocaluxe is an entirely new development in C#, inspired by the original UltraStar (developed by corvus5) +and the great Ultrastar Deluxe project. + +Supported Operating Systems / Requirements: +- WinXP, Vista, Windows 7 with .NET 2.0 +- 1 GHz CPU, 512 MB RAM, Graphics card with OpenGL 2.1 or DirectX 9.0 support + + +================================= += 2. Release Notes = +================================= + +- The program supports 32bit and 64bit (Vocaluxe_x64.exe) operating systems. + +- The program uses OpenGL as the default renderer. If your graphics card driver does not or not + properly support OpenGL, you can try the Direct3D renderer by editing your Config.xml in the + application's main directory: + + + + TR_CONFIG_DIRECT3D + +- To add your existing song collection to Vocaluxe, put your songs into the 'Songs' subfolder. + + Alternatively, you can add multiple song paths to Vocaluxe by editing your Config.xml: + + + + C:\Vocaluxe\Songs + D:\EvenMore\Songs + +- To use your highscore database from UltraStar deluxe 1.0.1, UltraStar deluxe CMD Mod or + UltraStar deluxe 1.1, simply copy your Ultrastar.db (rename if necessary) into the main + directory. Your highscore database will be imported into the HighscoreDB.sqlite file when + Vocaluxe is started. Upon successful import, the old database is deleted. + +- To add your own player avatars, simply add some picture files to the 'Profiles' subfolder. + Supported file types: png, jpg (jpeg), bmp. + Images should have square proportions, e.g. 400x400 px. + + +================================= += 3. Command-Line Parameters = +================================= +The following command-line parameters may be passed to the game when starting it through a shortcut +or from the console: + +-ConfigFile [Path\File]: Use [Path\File] as configuration file instead of Config.xml in the main folder. + The path to the file has to exist and needs to be an absolute path. + If only a filename is specified, the file is assumed to be in the current directory. + Examples: Vocaluxe.exe -ConfigFile MyConfig.xml + Vocaluxe.exe -ConfigFile C:\Vocaluxe\Configs\MyConfig.xml + +-ScoreFile [Path\File] : Use [File] as score database instead of HighscoreDB.sqlite in the application's + main folder. The path to the file has to exist and needs to be an absolute path. + If only a filename is specified, the file is assumed to be in the current directory. + Examples: Vocaluxe.exe -ScoreFile MyHighscoreDB.sqlite + Vocaluxe.exe -Scorefile C:\Vocaluxe\Highscores\MyHighscoreDB.sqlite + +-SongFolder [Path] : Use [Path] as song folder. The path has to exist and needs to be an absolute path. + Note that any song folders set in the config file will be ignored. + This parameter may be used multiple times to use different song folders. + Examples: Vocaluxe.exe -SongFolder D:\MySongCollection + Vocaluxe.exe -SongFolder D:\MySongCollection -SongFolder E:\MoreSongs + +-SongPath [Path] : Deprecated, see SongFolder [Path]. This alias is provided for convenience. + +Complete example: +Vocaluxe.exe -ConfigFile MyConfig.xml -ScoreFile C:\Vocaluxe\Highscores\MyHighscoreDB.sqlite -SongFolder D:\MySongCollection + + +================================= += 4. Controls = +================================= +[Mouse] to navigate through the screens: Left button: select/manipulate elements, + Right button: go to previous screen. +[Cursor] to navigate through the screens. +[Enter] to confirm +[Escape] or [Back] to go to the previous screen. + +[ALT] + [P] to take a ScreenShot. Screenshots are saved in the directory "Screenshots". +[ALT] + [ENTER] to toggle full screen mode. +[SHIFT] + [F1] to toggle theme edit mode. The theme edit mode is experimental. It allows you + to change the size and position of the element on the screens. You can save + your changes with [S] before leaving the theme edit mode. +[TAB] to open the background music controls (not on all screens). + +Songscreen +[R] to select a random song +[F3] or [CTRL]+[F] to open/close the song search menu +[A] to sing all songs from a category + + +================================= += 5. Help & Suppport = +================================= +Support Forum (German): http://www.ultra-star.de +Song-DataBase (USDB): http://usdb.animux.de/ + + +================================= += 6. Source Code = +================================= +Source Code (GitHub): https://github.com/Vocaluxe/Vocaluxe +SF.Net Page: http://sourceforge.net/projects/vocaluxe/ \ No newline at end of file diff --git a/Vocaluxe/Base/CDataBase.cs b/Vocaluxe/Base/CDataBase.cs index 90b52a93..4dec5522 100644 --- a/Vocaluxe/Base/CDataBase.cs +++ b/Vocaluxe/Base/CDataBase.cs @@ -38,10 +38,45 @@ namespace Vocaluxe.Base } #region Highscores + public static int AddScore(string PlayerName, int Score, int LineNr, long Date, int Medley, int Duet, int Diff, + string Artist, string Title, int NumPlayed, string FilePath) + { + SPlayer player = new SPlayer(); + player.Name = PlayerName; + player.Points = Score; + player.LineNr = LineNr; + player.DateTicks = Date; + player.Medley = (Medley == 1); + player.Duet = (Duet == 1); + player.Difficulty = (EGameDifficulty)Diff; + + SQLiteConnection connection = new SQLiteConnection(); + connection.ConnectionString = "Data Source=" + FilePath; + SQLiteCommand command; + + try + { + connection.Open(); + } + catch (Exception) + { + return -1; + } + + command = new SQLiteCommand(connection); + + int DataBaseSongID = GetDataBaseSongID(Artist, Title, NumPlayed, command); + int result = AddScore(player, command, DataBaseSongID); + + command.Dispose(); + connection.Close(); + connection.Dispose(); + + return result; + } + public static int AddScore(SPlayer player) { - int lastInsertID = -1; - SQLiteConnection connection = new SQLiteConnection(); connection.ConnectionString = "Data Source=" + _HighscoreFilePath; SQLiteCommand command; @@ -58,6 +93,18 @@ namespace Vocaluxe.Base command = new SQLiteCommand(connection); int DataBaseSongID = GetDataBaseSongID(player, command); + int result = AddScore(player, command, DataBaseSongID); + + connection.Close(); + connection.Dispose(); + + return result; + } + + private static int AddScore(SPlayer player, SQLiteCommand command, int DataBaseSongID) + { + int lastInsertID = -1; + if (DataBaseSongID >= 0) { @@ -68,7 +115,38 @@ namespace Vocaluxe.Base int Duet = 0; if (player.Duet) Duet = 1; + + command.CommandText = "SELECT id FROM Scores WHERE SongID = @SongID AND PlayerName = @PlayerName AND Score = @Score AND " + + "LineNr = @LineNr AND Date = @Date AND Medley = @Medley AND Duet = @Duet AND Difficulty = @Difficulty"; + command.Parameters.Add("@SongID", System.Data.DbType.Int32, 0).Value = DataBaseSongID; + command.Parameters.Add("@PlayerName", System.Data.DbType.String, 0).Value = player.Name; + command.Parameters.Add("@Score", System.Data.DbType.Int32, 0).Value = (int)Math.Round(player.Points); + command.Parameters.Add("@LineNr", System.Data.DbType.Int32, 0).Value = (int)player.LineNr; + command.Parameters.Add("@Date", System.Data.DbType.Int64, 0).Value = player.DateTicks; + command.Parameters.Add("@Medley", System.Data.DbType.Int32, 0).Value = Medley; + command.Parameters.Add("@Duet", System.Data.DbType.Int32, 0).Value = Duet; + command.Parameters.Add("@Difficulty", System.Data.DbType.Int32, 0).Value = (int)player.Difficulty; + SQLiteDataReader reader = null; + try + { + reader = command.ExecuteReader(); + } + catch (Exception) + { + ; + } + + if (reader != null && reader.HasRows) + { + if (reader.Read()) + return reader.GetInt32(0); + } + + if (reader != null) + reader.Close(); + + command.CommandText = "INSERT INTO Scores (SongID, PlayerName, Score, LineNr, Date, Medley, Duet, Difficulty) " + "VALUES (@SongID, @PlayerName, @Score, @LineNr, @Date, @Medley, @Duet, @Difficulty)"; command.Parameters.Add("@SongID", System.Data.DbType.Int32, 0).Value = DataBaseSongID; @@ -84,7 +162,7 @@ namespace Vocaluxe.Base //Read last insert line command.CommandText = "SELECT id FROM Scores ORDER BY Date DESC LIMIT 0, 1"; - SQLiteDataReader reader = null; + reader = null; try { reader = command.ExecuteReader(); @@ -106,10 +184,6 @@ namespace Vocaluxe.Base } } - command.Dispose(); - connection.Close(); - connection.Dispose(); - return lastInsertID; } @@ -194,9 +268,38 @@ namespace Vocaluxe.Base if (song == null) return -1; + return GetDataBaseSongID(song.Artist, song.Title, 0, command); + } + + private static int GetDataBaseSongID(string Artist, string Title, string FilePath, int DefNumPlayed) + { + SQLiteConnection connection = new SQLiteConnection(); + connection.ConnectionString = "Data Source=" + FilePath; + SQLiteCommand command; + + try + { + connection.Open(); + } + catch (Exception) + { + return -1; + } + + command = new SQLiteCommand(connection); + int id = GetDataBaseSongID(Artist, Title, DefNumPlayed, command); + command.Dispose(); + connection.Close(); + connection.Dispose(); + + return id; + } + + private static int GetDataBaseSongID(string Artist, string Title, int DefNumPlayed, SQLiteCommand command) + { command.CommandText = "SELECT id FROM Songs WHERE [Title] = @title AND [Artist] = @artist"; - command.Parameters.Add("@title", System.Data.DbType.String, 0).Value = song.Title; - command.Parameters.Add("@artist", System.Data.DbType.String, 0).Value = song.Artist; + command.Parameters.Add("@title", System.Data.DbType.String, 0).Value = Title; + command.Parameters.Add("@artist", System.Data.DbType.String, 0).Value = Artist; SQLiteDataReader reader = null; try @@ -222,14 +325,15 @@ namespace Vocaluxe.Base reader.Close(); command.CommandText = "INSERT INTO Songs (Title, Artist, NumPlayed) " + - "VALUES (@title, @artist, 0)"; - command.Parameters.Add("@title", System.Data.DbType.String, 0).Value = song.Title; - command.Parameters.Add("@artist", System.Data.DbType.String, 0).Value = song.Artist; + "VALUES (@title, @artist, @numplayed)"; + command.Parameters.Add("@title", System.Data.DbType.String, 0).Value = Title; + command.Parameters.Add("@artist", System.Data.DbType.String, 0).Value = Artist; + command.Parameters.Add("@numplayed", System.Data.DbType.Int32, 0).Value = DefNumPlayed; command.ExecuteNonQuery(); command.CommandText = "SELECT id FROM Songs WHERE [Title] = @title AND [Artist] = @artist"; - command.Parameters.Add("@title", System.Data.DbType.String, 0).Value = song.Title; - command.Parameters.Add("@artist", System.Data.DbType.String, 0).Value = song.Artist; + command.Parameters.Add("@title", System.Data.DbType.String, 0).Value = Title; + command.Parameters.Add("@artist", System.Data.DbType.String, 0).Value = Artist; reader = null; try @@ -260,10 +364,136 @@ namespace Vocaluxe.Base return -1; } - private static bool InitHighscoreDB() + private static bool GetDataBaseSongInfos(int SongID, out string Artist, out string Title, out int NumPlayed, string FilePath) + { + Artist = String.Empty; + Title = String.Empty; + NumPlayed = 0; + + SQLiteConnection connection = new SQLiteConnection(); + connection.ConnectionString = "Data Source=" + FilePath; + SQLiteCommand command; + + try + { + connection.Open(); + } + catch (Exception) + { + return false; + } + + command = new SQLiteCommand(connection); + command.CommandText = "SELECT Artist, Title, NumPlayed FROM Songs WHERE [id] = @id"; + command.Parameters.Add("@id", System.Data.DbType.String, 0).Value = SongID; + + SQLiteDataReader reader = null; + try + { + reader = command.ExecuteReader(); + } + catch (Exception) + { + return false; + } + + if (reader != null && reader.HasRows) + { + reader.Read(); + Artist = reader.GetString(0); + Title = reader.GetString(1); + NumPlayed = reader.GetInt32(2); + reader.Close(); + reader.Dispose(); + + command.Dispose(); + connection.Close(); + connection.Dispose(); + return true; + } + else + { + if (reader != null) + reader.Close(); + } + + command.Dispose(); + connection.Close(); + connection.Dispose(); + + return false; + } + + private static void InitHighscoreDB() + { + string OldDBFilePath = Path.Combine(Environment.CurrentDirectory, CSettings.sFileOldHighscoreDB); + if (File.Exists(OldDBFilePath)) + { + if (File.Exists(_HighscoreFilePath)) + { + CreateOrConvert(OldDBFilePath); + CreateOrConvert(_HighscoreFilePath); + ImportData(OldDBFilePath, _HighscoreFilePath); + + File.Delete(OldDBFilePath); + } + else + { + File.Copy(OldDBFilePath, _HighscoreFilePath); + CreateOrConvert(_HighscoreFilePath); + File.Delete(OldDBFilePath); + } + } + else + CreateOrConvert(_HighscoreFilePath); + } + + private static void CreateHighscoreDB(string FilePath) { SQLiteConnection connection = new SQLiteConnection(); - connection.ConnectionString = "Data Source=" + _HighscoreFilePath; + connection.ConnectionString = "Data Source=" + FilePath; + SQLiteCommand command; + + try + { + connection.Open(); + } + catch (Exception) + { + return; + } + + command = new SQLiteCommand(connection); + + command.CommandText = "CREATE TABLE IF NOT EXISTS Version ( id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, Value INTEGER NOT NULL);"; + command.ExecuteNonQuery(); + + command.CommandText = "INSERT INTO Version (id, Value) VALUES(NULL, " + CSettings.iDatabaseHighscoreVersion.ToString() + ")"; + command.ExecuteNonQuery(); + + command.CommandText = "CREATE TABLE IF NOT EXISTS Songs ( id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, " + + "Artist TEXT NOT NULL, Title TEXT NOT NULL, NumPlayed INTEGER);"; + command.ExecuteNonQuery(); + + command.CommandText = "CREATE TABLE IF NOT EXISTS Scores ( id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, " + + "SongID INTEGER NOT NULL, PlayerName TEXT NOT NULL, Score INTEGER NOT NULL, LineNr INTEGER NOT NULL, Date BIGINT NOT NULL, " + + "Medley INTEGER NOT NULL, Duet INTEGER NOT NULL, Difficulty INTEGER NOT NULL);"; + command.ExecuteNonQuery(); + + command.Dispose(); + connection.Close(); + connection.Dispose(); + } + + /// + /// Creates a new Vocaluxe Database if no file exists. Converts an existing old Ultrastar Deluxe highscore database into vocaluxe format. + /// + /// Database file path + /// + private static bool CreateOrConvert(string FilePath) + { + SQLiteConnection connection = new SQLiteConnection(); + connection.ConnectionString = "Data Source=" + FilePath; SQLiteCommand command; try @@ -292,12 +522,12 @@ namespace Vocaluxe.Base if (reader == null) { // create new database/tables - CreateHighscoreDB(); + CreateHighscoreDB(FilePath); } else if (reader.FieldCount == 0) { // create new database/tables - CreateHighscoreDB(); + CreateHighscoreDB(FilePath); } else { @@ -335,10 +565,10 @@ namespace Vocaluxe.Base //Check for USDX 1.1 DB if (version == 1) - ConvertFrom110(); + ConvertFrom110(FilePath); //Check for USDX 1.01 or CMD Mod DB else if (version == 0 && scoresTableExists) - ConvertFrom101(); + ConvertFrom101(FilePath); command.Dispose(); @@ -348,61 +578,15 @@ namespace Vocaluxe.Base return true; } - private static void CreateHighscoreDB() - { - SQLiteConnection connection = new SQLiteConnection(); - connection.ConnectionString = "Data Source=" + _HighscoreFilePath; - SQLiteCommand command; - - try - { - connection.Open(); - } - catch (Exception) - { - return; - } - - command = new SQLiteCommand(connection); - - command.CommandText = "CREATE TABLE IF NOT EXISTS Version ( id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, Value INTEGER NOT NULL);"; - command.ExecuteNonQuery(); - - command.CommandText = "INSERT INTO Version (id, Value) VALUES(NULL, " + CSettings.iDatabaseHighscoreVersion.ToString() + ")"; - command.ExecuteNonQuery(); - - command.CommandText = "CREATE TABLE IF NOT EXISTS Songs ( id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, " + - "Artist TEXT NOT NULL, Title TEXT NOT NULL, NumPlayed INTEGER);"; - command.ExecuteNonQuery(); - - command.CommandText = "CREATE TABLE IF NOT EXISTS Scores ( id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, " + - "SongID INTEGER NOT NULL, PlayerName TEXT NOT NULL, Score INTEGER NOT NULL, LineNr INTEGER NOT NULL, Date BIGINT NOT NULL, " + - "Medley INTEGER NOT NULL, Duet INTEGER NOT NULL, Difficulty INTEGER NOT NULL);"; - command.ExecuteNonQuery(); - - command.Dispose(); - connection.Close(); - connection.Dispose(); - - /* - // Auslesen des zuletzt eingefügten Datensatzes. - command.CommandText = "SELECT id, name FROM beispiel ORDER BY id DESC LIMIT 0, 1"; - - while (reader.Read()) - { - Console.WriteLine("Dies ist der {0}. eingefügte Datensatz mit dem Wert: \"{1}\"", reader[0].ToString(), reader[1].ToString()); - } - */ - } - /// /// Converts a USDX 1.1 database into the Vocaluxe format /// + /// Database file path /// True if succeeded - private static bool ConvertFrom110() + private static bool ConvertFrom110(string FilePath) { SQLiteConnection connection = new SQLiteConnection(); - connection.ConnectionString = "Data Source=" + _HighscoreFilePath; + connection.ConnectionString = "Data Source=" + FilePath; SQLiteCommand command; try @@ -520,11 +704,12 @@ namespace Vocaluxe.Base /// /// Converts a USDX 1.01 or CMD 1.01 database to Vocaluxe format /// + /// Database file path /// True if succeeded - private static bool ConvertFrom101() + private static bool ConvertFrom101(string FilePath) { SQLiteConnection connection = new SQLiteConnection(); - connection.ConnectionString = "Data Source=" + _HighscoreFilePath; + connection.ConnectionString = "Data Source=" + FilePath; SQLiteCommand command; SQLiteDataReader reader = null; @@ -577,11 +762,11 @@ namespace Vocaluxe.Base List songs = new List(); Sqlite3.sqlite3 OldDB; - int res = Sqlite3.sqlite3_open(_HighscoreFilePath, out OldDB); + int res = Sqlite3.sqlite3_open(FilePath, out OldDB); if (res != Sqlite3.SQLITE_OK) { - CLog.LogError("Error opening Database: " + _HighscoreFilePath + " (" + Sqlite3.sqlite3_errmsg(OldDB) + ")"); + CLog.LogError("Error opening Database: " + FilePath + " (" + Sqlite3.sqlite3_errmsg(OldDB) + ")"); } else { @@ -590,11 +775,11 @@ namespace Vocaluxe.Base if (res != Sqlite3.SQLITE_OK) { - CLog.LogError("Error query Database: " + _HighscoreFilePath + " (" + Sqlite3.sqlite3_errmsg(OldDB) + ")"); + CLog.LogError("Error query Database: " + FilePath + " (" + Sqlite3.sqlite3_errmsg(OldDB) + ")"); } else { - Sqlite3.sqlite3_step(Stmt); + //Sqlite3.sqlite3_step(Stmt); Encoding UTF8 = Encoding.UTF8; Encoding CP1252 = Encoding.GetEncoding(1252); @@ -625,11 +810,11 @@ namespace Vocaluxe.Base if (res != Sqlite3.SQLITE_OK) { - CLog.LogError("Error query Database: " + _HighscoreFilePath + " (" + Sqlite3.sqlite3_errmsg(OldDB) + ")"); + CLog.LogError("Error query Database: " + FilePath + " (" + Sqlite3.sqlite3_errmsg(OldDB) + ")"); } else { - Sqlite3.sqlite3_step(Stmt); + //Sqlite3.sqlite3_step(Stmt); Encoding UTF8 = Encoding.UTF8; Encoding CP1252 = Encoding.GetEncoding(1252); @@ -693,6 +878,71 @@ namespace Vocaluxe.Base return true; } + + private static bool ImportData(string SourceDBPath, string DestinationDBPath) + { + #region open db + SQLiteConnection connSource = new SQLiteConnection(); + connSource.ConnectionString = "Data Source=" + SourceDBPath; + + try + { + connSource.Open(); + } + catch (Exception e) + { + CLog.LogError("Error on import high score data. Can't open source database \"" + SourceDBPath + "\" (" + e.Message + ")"); + return false; + } + #endregion open db + + SQLiteCommand cmdSource = new SQLiteCommand(connSource); + SQLiteDataReader rSource; + + #region import table scores + cmdSource.CommandText = "SELECT SongID, PlayerName, Score, LineNr, Date, Medley, Duet, Difficulty FROM Scores"; + rSource = cmdSource.ExecuteReader(); + if (rSource == null) + { + cmdSource.Dispose(); + connSource.Close(); + return false; + } + + if (rSource.FieldCount == 0) + { + rSource.Close(); + cmdSource.Dispose(); + connSource.Close(); + return true; + } + + while (rSource.Read()) + { + int songid = rSource.GetInt32(0); + string player = rSource.GetString(1); + int score = rSource.GetInt32(2); + int linenr = rSource.GetInt32(3); + long date = rSource.GetInt64(4); + int medley = rSource.GetInt32(5); + int duet = rSource.GetInt32(6); + int diff = rSource.GetInt32(7); + + string artist, title; + int numplayed; + if (GetDataBaseSongInfos(songid, out artist, out title, out numplayed, SourceDBPath)) + { + AddScore(player, score, linenr, date, medley, duet, diff, artist, title, numplayed, _HighscoreFilePath); + } + } + #endregion import table scores + + rSource.Close(); + cmdSource.Dispose(); + connSource.Close(); + + return true; + } #endregion Highscores #region Cover diff --git a/Vocaluxe/Base/CDraw.cs b/Vocaluxe/Base/CDraw.cs index 514d3adc..3a62415b 100644 --- a/Vocaluxe/Base/CDraw.cs +++ b/Vocaluxe/Base/CDraw.cs @@ -319,6 +319,7 @@ namespace Vocaluxe.Base { #region private vars private string _TextureName; + private STexture _Texture; private SRectF _Rect; private float _Size; private SColorF _Color; @@ -333,7 +334,7 @@ namespace Vocaluxe.Base private float _Vsize; //size changing speed: period [s] private float _LastTime; private EParticeType _Type; - + private Stopwatch _Timer; #endregion private vars @@ -386,6 +387,7 @@ namespace Vocaluxe.Base public CParticle(string textureName, SColorF color, float x, float y, float size, float maxage, float z, float vx, float vy, float vr, float vsize, EParticeType type) { _TextureName = textureName; + _Texture = new STexture(-1); _Color = color; _Rect = new SRectF(x, y, size, size, z); _Size = size; @@ -403,6 +405,29 @@ namespace Vocaluxe.Base _MaxAge = maxage; _Rotation = (float)(CGame.Rand.NextDouble() * 360.0); } + + public CParticle(STexture texture, SColorF color, float x, float y, float size, float maxage, float z, float vx, float vy, float vr, float vsize, EParticeType type) + { + _TextureName = String.Empty; + _Texture = texture; + _Color = color; + _Rect = new SRectF(x, y, size, size, z); + _Size = size; + _Alpha = 1f; + _Angle = 0f; + _Vx = vx; + _Vy = vy; + _Vr = vr; + _Vsize = vsize; + _LastTime = 0f; + _Type = type; + + _Timer = new Stopwatch(); + _Age = 0f; + _MaxAge = maxage; + _Rotation = (float)(CGame.Rand.NextDouble() * 360.0); + } + #endregion Constructors public void Update() @@ -553,7 +578,10 @@ namespace Vocaluxe.Base public void Draw() { - CDraw.DrawTexture(CTheme.GetSkinTexture(_TextureName), _Rect, new SColorF(_Color.R, _Color.G, _Color.B, _Color.A * Alpha2 * _Alpha)); + if (_TextureName != String.Empty) + CDraw.DrawTexture(CTheme.GetSkinTexture(_TextureName), _Rect, new SColorF(_Color.R, _Color.G, _Color.B, _Color.A * Alpha2 * _Alpha)); + else + CDraw.DrawTexture(_Texture, _Rect, new SColorF(_Color.R, _Color.G, _Color.B, _Color.A * Alpha2 * _Alpha)); } } @@ -561,6 +589,7 @@ namespace Vocaluxe.Base { private List _Stars; private string _TextureName; + private STexture _Texture; private int _MaxNumber; private SRectF _Area; private SColorF _Color; @@ -579,12 +608,33 @@ namespace Vocaluxe.Base } } + public SRectF Area + { + get { return _Area; } + set { _Area = value; } + } + public CParticleEffect(int MaxNumber, SColorF Color, SRectF Area, string TextureName, float Size, EParticeType Type) { _Stars = new List(); _Area = Area; _Color = Color; _TextureName = TextureName; + _Texture = new STexture(-1); + _MaxNumber = MaxNumber; + _Size = Size; + _Type = Type; + _SpawnTimer = new Stopwatch(); + _NextSpawnTime = 0f; + } + + public CParticleEffect(int MaxNumber, SColorF Color, SRectF Area, STexture texture, float Size, EParticeType Type) + { + _Stars = new List(); + _Area = Area; + _Color = Color; + _TextureName = String.Empty; + _Texture = texture; _MaxNumber = MaxNumber; _Size = Size; _Type = Type; @@ -682,10 +732,21 @@ namespace Vocaluxe.Base if (h < 0) h = 0; - CParticle star = new CParticle(_TextureName, _Color, - CGame.Rand.Next(w) + _Area.X - size / 4f, - CGame.Rand.Next(h) + _Area.Y - size / 4f, - size, lifetime, _Area.Z, vx, vy, vr, vsize, _Type); + CParticle star; + if (_TextureName != String.Empty) + { + star = new CParticle(_TextureName, _Color, + CGame.Rand.Next(w) + _Area.X - size / 4f, + CGame.Rand.Next(h) + _Area.Y - size / 4f, + size, lifetime, _Area.Z, vx, vy, vr, vsize, _Type); + } + else + { + star = new CParticle(_Texture, _Color, + CGame.Rand.Next(w) + _Area.X - size / 4f, + CGame.Rand.Next(h) + _Area.Y - size / 4f, + size, lifetime, _Area.Z, vx, vy, vr, vsize, _Type); + } _Stars.Add(star); } diff --git a/Vocaluxe/Base/CGame.cs b/Vocaluxe/Base/CGame.cs index 07ea2d2d..9c2b6c7d 100644 --- a/Vocaluxe/Base/CGame.cs +++ b/Vocaluxe/Base/CGame.cs @@ -247,72 +247,60 @@ namespace Vocaluxe.Base for (int p = 0; p < _NumPlayer; p++) { - CSound.AnalyzeBuffer(p); - - if (CSound.RecordToneValid(p) || DEBUG_HIT) + + for (int beat = _OldBeatD + 1; beat <= _CurrentBeatD; beat++) { - for (int beat = _OldBeatD + 1; beat <= _CurrentBeatD; beat++) - { - CLine[] lines = song.Notes.GetLines(_Player[p].LineNr).Line; - int Line = -1; + CLine[] lines = song.Notes.GetLines(_Player[p].LineNr).Line; + int Line = -1; - for (int j = 0; j < lines.Length; j++) + for (int j = 0; j < lines.Length; j++) + { + if (beat >= lines[j].StartBeat && beat <= lines[j].EndBeat) { - if (beat >= lines[j].StartBeat && beat <= lines[j].EndBeat) - { - Line = j; - break; - } + Line = j; + break; + } + } + + if (Line >= 0) + { + if (Line != _Player[p].CurrentLine) + _Player[p].CurrentNote = -1; + + _Player[p].CurrentLine = Line; + + while (_Player[p].SingLine.Count <= Line) + { + _Player[p].SingLine.Add(new CLine()); } - if (Line >= 0) + CNote[] notes = lines[Line].Notes; + int Note = -1; + for (int j = 0; j < notes.Length; j++) { - if (Line != _Player[p].CurrentLine) - _Player[p].CurrentNote = -1; - - _Player[p].CurrentLine = Line; - - while (_Player[p].SingLine.Count <= Line) + if (beat >= notes[j].StartBeat && beat <= notes[j].EndBeat) { - _Player[p].SingLine.Add(new CLine()); + Note = j; + break; } + } - CNote[] notes = lines[Line].Notes; - int Note = -1; - for (int j = 0; j < notes.Length; j++) - { - if (beat >= notes[j].StartBeat && beat <= notes[j].EndBeat) - { - if (notes[j].PointsForBeat > 0) - Note = j; - break; - } - } + if (Note >= 0) + { + _Player[p].CurrentNote = Note; - if (Note >= 0) + if (Line == lines.Length - 1) { - if (Line == lines.Length - 1) + if (Note == lines[Line].NoteCount - 1) { - if (Note == lines[Line].NoteCount - 1) - { + if (notes[Note].EndBeat == beat) _Player[p].SongFinished = true; - } } } - if (Note >= 0 && notes[Note].PointsForBeat > 0) + CSound.AnalyzeBuffer(p); + if (notes[Note].PointsForBeat > 0 && (CSound.RecordToneValid(p) || DEBUG_HIT)) { - _Player[p].CurrentNote = Note; - - if (Line == lines.Length - 1) - { - if (Note == lines[Line].NoteCount - 1) - { - if (notes[Note].EndBeat == beat) - _Player[p].SongFinished = true; - } - } - int Tone = notes[Note].Tone; int TonePlayer = CSound.RecordGetTone(p); @@ -383,8 +371,8 @@ namespace Vocaluxe.Base } } } - } + } } _OldBeatD = _CurrentBeatD; diff --git a/Vocaluxe/Base/CSettings.cs b/Vocaluxe/Base/CSettings.cs index bbd6164f..a1aa2db7 100644 --- a/Vocaluxe/Base/CSettings.cs +++ b/Vocaluxe/Base/CSettings.cs @@ -69,6 +69,7 @@ namespace Vocaluxe.Base public const string sFileCover = "Cover.xml"; public const string sFileFonts = "Fonts.xml"; + public const string sFileOldHighscoreDB = "Ultrastar.db"; public static string sFileHighscoreDB = "HighscoreDB.sqlite"; public const string sFileCoverDB = "CoverDB.sqlite"; public const string sFilePerformanceLog = "Performance.log"; diff --git a/Vocaluxe/Doc/Roadmap.txt b/Vocaluxe/Doc/Roadmap.txt index ed4f88e1..66024f04 100644 --- a/Vocaluxe/Doc/Roadmap.txt +++ b/Vocaluxe/Doc/Roadmap.txt @@ -79,7 +79,8 @@ + v0.2.0: - Medley - WiiMote Support - - Jukebox light + - Jukebox light (bg music controls) + - Show Avatars and Player Name in Sing Screen (and perhaps some other screens) + v0.3.0: - Song Editor diff --git a/Vocaluxe/Lib/Song/CSong.cs b/Vocaluxe/Lib/Song/CSong.cs index 39c1d35f..1327363b 100644 --- a/Vocaluxe/Lib/Song/CSong.cs +++ b/Vocaluxe/Lib/Song/CSong.cs @@ -237,6 +237,11 @@ namespace Vocaluxe.Lib.Song this.MP3FileName = Value; HeaderFlags |= EHeaderFlags.MP3; } + else + { + CLog.LogError("Can't find audio file: " + Path.Combine(this.Folder, Value)); + return false; + } break; case "BPM": if (CHelper.TryParse(Value, out this.BPM)) @@ -283,6 +288,9 @@ namespace Vocaluxe.Lib.Song case "VIDEO": if (File.Exists(Path.Combine(this.Folder, Value))) this.VideoFileName = Value; + else + CLog.LogError("Can't find video file: " + Path.Combine(this.Folder, Value)); + break; case "VIDEOGAP": CHelper.TryParse(Value, out this.VideoGap); diff --git a/Vocaluxe/Program.cs b/Vocaluxe/Program.cs index 6ff04a93..940951f5 100644 --- a/Vocaluxe/Program.cs +++ b/Vocaluxe/Program.cs @@ -141,7 +141,7 @@ namespace Vocaluxe CLog.StopBenchmark(0, "Init Game"); Application.DoEvents(); - + System.Threading.Thread.Sleep(10000); // Start Main Loop _SplashScreen.Close(); CDraw.MainLoop(); @@ -192,6 +192,8 @@ namespace Vocaluxe class SplashScreen : Form { + Bitmap logo; + public SplashScreen() { string path = Path.Combine(Environment.CurrentDirectory, Path.Combine(CSettings.sFolderGraphics, CSettings.sLogo)); @@ -199,9 +201,8 @@ namespace Vocaluxe { try { - Bitmap logo = new Bitmap(path); + logo = new Bitmap(path); this.ClientSize = new Size(logo.Width, logo.Height); - this.BackgroundImage = logo; } catch (Exception e) { @@ -226,11 +227,27 @@ namespace Vocaluxe } else CLog.LogError("Can't find " + path); - + + SetStyle(ControlStyles.SupportsTransparentBackColor, true); + this.BackColor = Color.Transparent; + this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.None; this.Text = CSettings.sProgramName; this.CenterToScreen(); this.Show(); } + + protected override void OnPaint(System.Windows.Forms.PaintEventArgs e) + { + } + + protected override void OnPaintBackground(System.Windows.Forms.PaintEventArgs e) + { + if (logo == null) + return; + + Graphics g = e.Graphics; + g.DrawImage(logo, new Rectangle(0, 0, this.Width, this.Height)); + } } } diff --git a/Vocaluxe/Screens/CScreenSing.cs b/Vocaluxe/Screens/CScreenSing.cs index 48ea1105..8e947a04 100644 --- a/Vocaluxe/Screens/CScreenSing.cs +++ b/Vocaluxe/Screens/CScreenSing.cs @@ -581,7 +581,8 @@ namespace Vocaluxe.Screens lines[i] = song.Notes.GetLines(i); CLine[] line = lines[i].Line; - + + // find current line (it must be the same as in CalcFadingAlpha) int nr = -1; for (int j = 0; j < line.Length; j++) { @@ -850,6 +851,20 @@ namespace Vocaluxe.Screens lines[i] = Song.Notes.GetLines(i); CLine[] line = lines[i].Line; + // find current line for lyric sub fading (it must be the same as in UpdateLyrics) + int CurrentLineSub = 0; + for (int j = 0; j < line.Length; j++) + { + if (line[j].StartBeat <= _CurrentBeat) + { + if (CGame.GetTimeFromBeats(line[j].FirstBeat, Song.BPM) <= _CurrentTime - Song.Gap + 10f) + { + CurrentLineSub = j; + } + } + } + + // find current line for lyric main fading int CurrentLine = 0; for (int j = 0; j < line.Length; j++) { @@ -863,9 +878,11 @@ namespace Vocaluxe.Screens Alpha[i * 2] = 1f; Alpha[i * 2 + 1] = 1f; - // main + // main line alpha if (CurrentLine == 0 && CurrentTime < CGame.GetTimeFromBeats(line[CurrentLine].FirstBeat, Song.BPM)) { + // first main line and fist note is not reached + // => fade in float diff = CGame.GetTimeFromBeats(line[CurrentLine].FirstBeat, Song.BPM) - CurrentTime; if (diff > dt) { @@ -875,20 +892,29 @@ namespace Vocaluxe.Screens else if (CurrentLine < line.Length - 1 && CGame.GetTimeFromBeats(line[CurrentLine].LastBeat, Song.BPM) < CurrentTime && CGame.GetTimeFromBeats(line[CurrentLine + 1].FirstBeat, Song.BPM) > CurrentTime) { + // current position is between two lines + + // time between the to lines float diff = CGame.GetTimeFromBeats(line[CurrentLine + 1].FirstBeat, Song.BPM) - CGame.GetTimeFromBeats(line[CurrentLine].LastBeat, Song.BPM); + // fade only if there is enough time for fading if (diff > 3.3f * dt) { + // time elapsed since last line float last = CurrentTime - CGame.GetTimeFromBeats(line[CurrentLine].LastBeat, Song.BPM); + + // time to next line float next = CGame.GetTimeFromBeats(line[CurrentLine + 1].FirstBeat, Song.BPM) - CurrentTime; if (last < next) { + // fade out Alpha[i * 2] = 1f - last / rt; } else { + // fade in if it is time for if (next > dt) Alpha[i * 2] = 1f - (next - dt) / rt; } @@ -896,14 +922,18 @@ namespace Vocaluxe.Screens } else if (CurrentLine == line.Length - 1 && CGame.GetTimeFromBeats(line[CurrentLine].LastBeat, Song.BPM) < CurrentTime) { + // last main line and last note was reached + // => fade out float diff = CurrentTime - CGame.GetTimeFromBeats(line[CurrentLine].LastBeat, Song.BPM); Alpha[i * 2] = 1f - diff / rt; } // sub - if (CurrentLine < line.Length - 2) + if (CurrentLineSub < line.Length - 2) { - float diff = CGame.GetTimeFromBeats(line[CurrentLine + 1].FirstBeat, Song.BPM) - CurrentTime; + float diff = 0f; + diff = CGame.GetTimeFromBeats(line[CurrentLineSub + 1].FirstBeat, Song.BPM) - CurrentTime; + if (diff > dt) { Alpha[i * 2 + 1] = 1f - (diff - dt) / rt;