diff options
Diffstat (limited to 'unicode/src/base')
28 files changed, 2371 insertions, 2067 deletions
diff --git a/unicode/src/base/TextGL.pas b/unicode/src/base/TextGL.pas index 28c3c6b6..667a224f 100644 --- a/unicode/src/base/TextGL.pas +++ b/unicode/src/base/TextGL.pas @@ -68,11 +68,12 @@ procedure SetFontReflection(Enable:boolean;Spacing: real); // enables/disables t implementation uses - UMain, - UCommon, UTextEncoding, SysUtils, - IniFiles; + IniFiles, + UCommon, + UMain, + UPath; function FindFontFile(FontIni: TCustomIniFile; Font: string): string; var diff --git a/unicode/src/base/UCatCovers.pas b/unicode/src/base/UCatCovers.pas index 4fc54199..6ef81b68 100644 --- a/unicode/src/base/UCatCovers.pas +++ b/unicode/src/base/UCatCovers.pas @@ -64,8 +64,9 @@ uses SysUtils, Classes, // UFiles, + ULog, UMain, - ULog; + UPath; constructor TCatCovers.Create; begin diff --git a/unicode/src/base/UCore.pas b/unicode/src/base/UCore.pas index 901f2f96..a7f9e56e 100644 --- a/unicode/src/base/UCore.pas +++ b/unicode/src/base/UCore.pas @@ -42,20 +42,20 @@ uses {********************* TCore - Class manages all CoreModules, teh StartUp, teh MainLoop and the shutdown process - Also it does some Error Handling, and maybe sometime multithreaded Loading ;) + Class manages all CoreModules, the StartUp, the MainLoop and the shutdown process + Also, it does some error handling, and maybe sometime multithreaded loading ;) *********************} type TModuleListItem = record - Module: TCoreModule; //Instance of the Modules Class - Info: TModuleInfo; //ModuleInfo returned by Modules Modulinfo Proc - NeedsDeInit: Boolean; //True if Module was succesful inited + Module: TCoreModule; // Instance of the modules class + Info: TModuleInfo; // ModuleInfo returned by modules modulinfo proc + NeedsDeInit: boolean; // True if module was succesful inited end; TCore = class private - //Some Hook Handles. See Plugin SDKs Hooks.txt for Infos + // Some Hook Handles. See Plugin SDKs Hooks.txt for Infos hLoadingFinished: THandle; hMainLoop: THandle; hTranslate: THandle; @@ -72,71 +72,71 @@ type sGetModuleInfo: THandle; sGetApplicationHandle: THandle; - Modules: Array [0..High(CORE_MODULES_TO_LOAD)] of TModuleListItem; + Modules: array [0..High(CORE_MODULES_TO_LOAD)] of TModuleListItem; - //Cur + Last Executed Setting and Getting ;) - iCurExecuted: Integer; - iLastExecuted: Integer; + // Cur + Last Executed Setting and Getting ;) + iCurExecuted: integer; + iLastExecuted: integer; - procedure SetCurExecuted(Value: Integer); + procedure SetCurExecuted(Value: integer); - //Function Get all Modules and Creates them - function GetModules: Boolean; + // Function Get all Modules and Creates them + function GetModules: boolean; - //Loads Core and all Modules - function Load: Boolean; + // Loads Core and all Modules + function Load: boolean; - //Inits Core and all Modules - function Init: Boolean; + // Inits Core and all Modules + function Init: boolean; - //DeInits Core and all Modules - function DeInit: Boolean; + // DeInits Core and all Modules + function DeInit: boolean; - //Load the Core - function LoadCore: Boolean; + // Load the Core + function LoadCore: boolean; - //Init the Core - function InitCore: Boolean; + // Init the Core + function InitCore: boolean; - //DeInit the Core - function DeInitCore: Boolean; + // DeInit the Core + function DeInitCore: boolean; - //Called one Time per Frame - function MainLoop: Boolean; + // Called one time per frame + function MainLoop: boolean; public - Hooks: THookManager; //Teh Hook Manager ;) - Services: TServiceManager;//The Service Manager + Hooks: THookManager; // The Hook Manager ;) + Services: TServiceManager; // The Service Manager - Name: String; //Name of this Application - Version: LongWord; //Version of this ". For Info Look PluginDefs Functions + Name: string; // Name of this application + Version: LongWord; // Version of this ". For info look plugindefs functions - LastErrorReporter:String; //Who Reported the Last Error String - LastErrorString: String; //Last Error String reported + LastErrorReporter: string; // Who reported the last error string + LastErrorString: string; // Last error string reported - property CurExecuted: Integer read iCurExecuted write SetCurExecuted; //ID of Plugin or Module curently Executed - property LastExecuted: Integer read iLastExecuted; + property CurExecuted: integer read iCurExecuted write SetCurExecuted; //ID of plugin or module curently executed + property LastExecuted: integer read iLastExecuted; //--------------- - //Main Methods to control the Core: + // Main methods to control the core: //--------------- - constructor Create(const cName: String; const cVersion: LongWord); + constructor Create(const cName: string; const cVersion: LongWord); - //Starts Loading and Init Process. Then Runs MainLoop. DeInits on Shutdown + // Starts loading and init process. Then runs MainLoop. DeInits on shutdown procedure Run; - //Method for other Classes to get Pointer to a specific Module - function GetModulebyName(const Name: String): PCoreModule; + // Method for other classes to get pointer to a specific module + function GetModulebyName(const Name: string): PCoreModule; //-------------- - // Hook and Service Procs: + // Hook and service procs: //-------------- function ShowMessage(wParam: TwParam; lParam: TlParam): integer; //Shows a Message (lParam: PChar Text, wParam: Symbol) function ReportError(wParam: TwParam; lParam: TlParam): integer; //Shows a Message (wParam: Pchar(Message), lParam: PChar(Reportername)) function ReportDebug(wParam: TwParam; lParam: TlParam): integer; //Shows a Message (wParam: Pchar(Message), lParam: PChar(Reportername)) function Retranslate(wParam: TwParam; lParam: TlParam): integer; //Calls Translate hook function ReloadTextures(wParam: TwParam; lParam: TlParam): integer; //Calls LoadTextures hook - function GetModuleInfo(wParam: TwParam; lParam: TlParam): integer; //If lParam = nil then get length of Moduleinfo Array. If lparam <> nil then write array of TModuleInfo to address at lparam + function GetModuleInfo(wParam: TwParam; lParam: TlParam): integer; //If lParam = nil then get length of Moduleinfo array. If lparam <> nil then write array of TModuleInfo to address at lparam function GetApplicationHandle(wParam: TwParam; lParam: TlParam): integer; //Returns Application Handle end; @@ -154,7 +154,7 @@ uses //------------- // Create - Creates Class + Hook and Service Manager //------------- -constructor TCore.Create(const cName: String; const cVersion: LongWord); +constructor TCore.Create(const cName: string; const cVersion: LongWord); begin inherited Create; @@ -171,11 +171,11 @@ begin end; //------------- -//Starts Loading and Init Process. Then Runs MainLoop. DeInits on Shutdown +// Starts Loading and Init process. Then runs MainLoop. DeInits on shutdown //------------- procedure TCore.Run; var - Success: Boolean; + Success: boolean; procedure HandleError(const ErrorMsg: string); begin @@ -184,16 +184,16 @@ var else Self.ShowMessage(CORE_SM_ERROR, PChar(ErrorMsg)); - //DeInit + // DeInit DeInit; end; begin - //Get Modules + // Get modules try Success := GetModules(); except - Success := False; + Success := false; end; if (not Success) then @@ -202,11 +202,11 @@ begin Exit; end; - //Loading + // Loading try Success := Load(); except - Success := False; + Success := false; end; if (not Success) then @@ -215,11 +215,11 @@ begin Exit; end; - //Init + // Init try Success := Init(); except - Success := False; + Success := false; end; if (not Success) then @@ -228,28 +228,28 @@ begin Exit; end; - //Call Translate Hook + // Call Translate Hook if (Hooks.CallEventChain(hTranslate, 0, nil) <> 0) then begin HandleError('Error translating'); Exit; end; - //Calls LoadTextures Hook + // Calls LoadTextures Hook if (Hooks.CallEventChain(hLoadTextures, 0, nil) <> 0) then begin HandleError('Error loading textures'); Exit; end; - //Calls Loading Finished Hook + // Calls Loading Finished Hook if (Hooks.CallEventChain(hLoadingFinished, 0, nil) <> 0) then begin HandleError('Error calling LoadingFinished Hook'); Exit; end; - //Start MainLoop + // Start MainLoop while Success do begin Success := MainLoop(); @@ -258,41 +258,41 @@ begin end; //------------- -//Called one Time per Frame +// Called one time per frame //------------- -function TCore.MainLoop: Boolean; +function TCore.MainLoop: boolean; begin - Result := False; + Result := false; end; //------------- -//Function Get all Modules and Creates them +// Function get all modules and creates them //------------- -function TCore.GetModules: Boolean; +function TCore.GetModules: boolean; var - i: Integer; + i: integer; begin - Result := False; + Result := false; for i := 0 to high(Modules) do begin try - Modules[i].NeedsDeInit := False; + Modules[i].NeedsDeInit := false; Modules[i].Module := CORE_MODULES_TO_LOAD[i].Create; Modules[i].Module.Info(@Modules[i].Info); except - ReportError(Integer(PChar('Can''t get module #' + InttoStr(i) + ' "' + Modules[i].Info.Name + '"')), PChar('Core')); + ReportError(integer(PChar('Can''t get module #' + InttoStr(i) + ' "' + Modules[i].Info.Name + '"')), PChar('Core')); Exit; end; end; - Result := True; + Result := true; end; //------------- -//Loads Core and all Modules +// Loads core and all modules //------------- -function TCore.Load: Boolean; +function TCore.Load: boolean; var - i: Integer; + i: integer; begin Result := LoadCore; @@ -301,23 +301,23 @@ begin try Result := Modules[i].Module.Load; except - Result := False; + Result := false; end; if (not Result) then begin - ReportError(Integer(PChar('Error loading module #' + InttoStr(i) + ' "' + Modules[i].Info.Name + '"')), PChar('Core')); + ReportError(integer(PChar('Error loading module #' + InttoStr(i) + ' "' + Modules[i].Info.Name + '"')), PChar('Core')); break; end; end; end; //------------- -//Inits Core and all Modules +// Inits core and all modules //------------- -function TCore.Init: Boolean; +function TCore.Init: boolean; var - i: Integer; + i: integer; begin Result := InitCore; @@ -326,12 +326,12 @@ begin try Result := Modules[i].Module.Init; except - Result := False; + Result := false; end; if (not Result) then begin - ReportError(Integer(PChar('Error initing module #' + InttoStr(i) + ' "' + Modules[i].Info.Name + '"')), PChar('Core')); + ReportError(integer(PChar('Error initing module #' + InttoStr(i) + ' "' + Modules[i].Info.Name + '"')), PChar('Core')); break; end; @@ -340,7 +340,7 @@ begin end; //------------- -//DeInits Core and all Modules +// DeInits core and all modules //------------- function TCore.DeInit: boolean; var @@ -362,9 +362,9 @@ begin end; //------------- -//Load the Core +// Load the Core //------------- -function TCore.LoadCore: Boolean; +function TCore.LoadCore: boolean; begin hLoadingFinished := Hooks.AddEvent('Core/LoadingFinished'); hMainLoop := Hooks.AddEvent('Core/MainLoop'); @@ -383,35 +383,35 @@ begin sGetModuleInfo := Services.AddService('Core/GetModuleInfo', nil, Self.GetModuleInfo); sGetApplicationHandle := Services.AddService('Core/GetApplicationHandle', nil, Self.GetApplicationHandle); - //A little Test + // A little Test Hooks.AddSubscriber('Core/NewError', HookTest); result := true; end; //------------- -//Init the Core +// Init the Core //------------- -function TCore.InitCore: Boolean; +function TCore.InitCore: boolean; begin //Don not init something atm. result := true; end; //------------- -//DeInit the Core +// DeInit the Core //------------- -function TCore.DeInitCore: Boolean; +function TCore.DeInitCore: boolean; begin - // TODO: write TService-/HookManager.Free and call it here + // TODO: write TService-/HookManager. Free and call it here Result := true; end; //------------- -//Method for other classes to get pointer to a specific module +// Method for other classes to get pointer to a specific module //------------- -function TCore.GetModuleByName(const Name: String): PCoreModule; -var i: Integer; +function TCore.GetModuleByName(const Name: string): PCoreModule; +var i: integer; begin Result := nil; for i := 0 to High(Modules) do @@ -444,7 +444,7 @@ begin CORE_SM_INFO: Params := Params or MB_ICONINFORMATION; end; - //Show: + // Show: Result := Messagebox(0, lParam, PChar(Name), Params); end; {$ENDIF} @@ -458,8 +458,8 @@ end; function TCore.ReportError(wParam: TwParam; lParam: TlParam): integer; begin //Update LastErrorReporter and LastErrorString - LastErrorReporter := String(PChar(lParam)); - LastErrorString := String(PChar(Pointer(wParam))); + LastErrorReporter := string(PChar(lParam)); + LastErrorString := string(PChar(Pointer(wParam))); Hooks.CallEventChain(hError, wParam, lParam); @@ -501,7 +501,7 @@ begin end; //------------- -// If lParam = nil then get length of Moduleinfo Array. If lparam <> nil then write array of TModuleInfo to address at lparam +// If lParam = nil then get length of Moduleinfo array. If lparam <> nil then write array of TModuleInfo to address at lparam //------------- function TCore.GetModuleInfo(wParam: TwParam; lParam: TlParam): integer; var @@ -538,12 +538,12 @@ end; //------------- // Called when setting CurExecuted //------------- -procedure TCore.SetCurExecuted(Value: Integer); +procedure TCore.SetCurExecuted(Value: integer); begin - //Set Last Executed + // Set Last Executed iLastExecuted := iCurExecuted; - //Set Cur Executed + // Set Cur Executed iCurExecuted := Value; end; diff --git a/unicode/src/base/UDraw.pas b/unicode/src/base/UDraw.pas index d3f19019..8a66d271 100644 --- a/unicode/src/base/UDraw.pas +++ b/unicode/src/base/UDraw.pas @@ -55,7 +55,6 @@ procedure SingDrawTimeBar(); //Draw Editor NoteLines procedure EditDrawLine(Left, Top, Right: real; NrLines: integer; Space: integer); - type TRecR = record Top: real; @@ -67,7 +66,6 @@ type WMid: real; Height: real; HMid: real; - Mid: real; end; @@ -75,51 +73,45 @@ var NotesW: real; NotesH: real; Starfr: integer; - StarfrG: integer; + StarfrG: integer; //SingBar - TickOld: cardinal; - TickOld2:cardinal; - -const - Przedz = 32; + TickOld: cardinal; + TickOld2: cardinal; implementation uses + SysUtils, + Math, gl, + TextGL, + UDLLManager, + UDrawTexture, UGraphic, - SysUtils, + UIni, + ULog, + ULyrics, + UNote, UMusic, URecord, - ULog, UScreenSing, UScreenSingModi, - ULyrics, - UMain, - TextGL, - UTexture, - UDrawTexture, - UIni, - Math, - UDLLManager; + UTexture; procedure SingDrawBackground; var - Rec: TRecR; - TexRec: TRecR; + Rec: TRecR; + TexRec: TRecR; begin - if (ScreenSing.Tex_Background.TexNum > 0) then begin - - glClearColor (1, 1, 1, 1); - glColor4f (1, 1, 1, 1); - + if (ScreenSing.Tex_Background.TexNum > 0) then + begin if (Ini.MovieSize <= 1) then //HalfSize BG begin (* half screen + gradient *) Rec.Top := 110; // 80 Rec.Bottom := Rec.Top + 20; - Rec.Left := 0; + Rec.Left := 0; Rec.Right := 800; TexRec.Top := (Rec.Top / 600) * ScreenSing.Tex_Background.TexH; @@ -185,16 +177,17 @@ end; procedure SingDrawOscilloscope(X, Y, W, H: real; NrSound: integer); var SampleIndex: integer; - Sound: TCaptureBuffer; - MaxX, MaxY: real; + Sound: TCaptureBuffer; + MaxX, MaxY: real; begin; Sound := AudioInputProcessor.Sound[NrSound]; // Log.LogStatus('Oscilloscope', 'SingDraw'); glColor3f(Skin_OscR, Skin_OscG, Skin_OscB); - {if (ParamStr(1) = '-black') or (ParamStr(1) = '-fsblack') then - glColor3f(1, 1, 1); } - +{ + if (ParamStr(1) = '-black') or (ParamStr(1) = '-fsblack') then + glColor3f(1, 1, 1); +} MaxX := W-1; MaxY := (H-1) / 2; @@ -211,16 +204,15 @@ begin; Sound.UnlockAnalysisBuffer(); end; - - procedure SingDrawNoteLines(Left, Top, Right: real; Space: integer); var - Count: integer; + Count: integer; begin glEnable(GL_BLEND); glColor4f(Skin_P1_LinesR, Skin_P1_LinesG, Skin_P1_LinesB, 0.4); glBegin(GL_LINES); - for Count := 0 to 9 do begin + for Count := 0 to 9 do + begin glVertex2f(Left, Top + Count * Space); glVertex2f(Right, Top + Count * Space); end; @@ -230,13 +222,14 @@ end; procedure SingDrawBeatDelimeters(Left, Top, Right: real; NrLines: integer); var - Count: integer; - TempR: real; + Count: integer; + TempR: real; begin TempR := (Right-Left) / (Lines[NrLines].Line[Lines[NrLines].Current].End_ - Lines[NrLines].Line[Lines[NrLines].Current].Note[0].Start); glEnable(GL_BLEND); glBegin(GL_LINES); - for Count := Lines[NrLines].Line[Lines[NrLines].Current].Note[0].Start to Lines[NrLines].Line[Lines[NrLines].Current].End_ do begin + for Count := Lines[NrLines].Line[Lines[NrLines].Current].Note[0].Start to Lines[NrLines].Line[Lines[NrLines].Current].End_ do + begin if (Count mod Lines[NrLines].Resolution) = Lines[NrLines].NotesGAP then glColor4f(0, 0, 0, 1) else @@ -251,18 +244,17 @@ end; // draw blank Notebars procedure SingDrawLine(Left, Top, Right: real; NrLines: integer; Space: integer); var - Rec: TRecR; - Count: integer; - TempR: real; + Rec: TRecR; + Count: integer; + TempR: real; - PlayerNumber: Integer; + PlayerNumber: integer; - GoldenStarPos : real; - - lTmpA , - lTmpB : real; + GoldenStarPos: real; + + lTmpA, lTmpB : real; begin -// We actually don't have a playernumber in this procedure, it should reside in NrLines - but it's always set to zero +// We actually don't have a playernumber in this procedure, it should reside in NrLines - but it is always set to zero // So we exploit this behavior a bit - we give NrLines the playernumber, keep it in playernumber - and then we set NrLines to zero // This could also come quite in handy when we do the duet mode, cause just the notes for the player that has to sing should be drawn then // BUT this is not implemented yet, all notes are drawn! :D @@ -280,23 +272,19 @@ begin lTmpA := (Right-Left); lTmpB := (Lines[NrLines].Line[Lines[NrLines].Current].End_ - Lines[NrLines].Line[Lines[NrLines].Current].Note[0].Start); - if ( lTmpA > 0 ) AND - ( lTmpB > 0 ) THEN - begin - TempR := lTmpA / lTmpB; - end + if ( lTmpA > 0 ) and ( lTmpB > 0 ) then + TempR := lTmpA / lTmpB else - begin TempR := 0; - end; - - - with Lines[NrLines].Line[Lines[NrLines].Current] do begin - for Count := 0 to HighNote do begin - with Note[Count] do begin - if NoteType <> ntFreestyle then begin - + with Lines[NrLines].Line[Lines[NrLines].Current] do + begin + for Count := 0 to HighNote do + begin + with Note[Count] do + begin + if NoteType <> ntFreestyle then + begin if Ini.EffectSing = 0 then // If Golden note Effect of then Change not Color begin @@ -307,9 +295,9 @@ begin end //Else all Notes same Color else glColor4f(1, 1, 1, 1); // We set alpha to 1, cause we can control the transparency through the png itself - // Czesci == teil, element == piece, element | koniec == end / ending - // lewa czesc - left part - Rec.Left := (Start-Lines[NrLines].Line[Lines[NrLines].Current].Note[0].Start) * TempR + Left + 0.5 + 10*ScreenX; + + // left part + Rec.Left := (Start-Lines[NrLines].Line[Lines[NrLines].Current].Note[0].Start) * TempR + Left + 0.5 + 10*ScreenX; Rec.Right := Rec.Left + NotesW; Rec.Top := Top - (Tone-BaseNote)*Space/2 - NotesH; Rec.Bottom := Rec.Top + 2 * NotesH; @@ -326,8 +314,8 @@ begin //done // middle part - Rec.Left := Rec.Right; - Rec.Right := (Start+Length-Lines[NrLines].Line[Lines[NrLines].Current].Note[0].Start) * TempR + Left - NotesW - 0.5 + 10*ScreenX; // Dlugosc == length + Rec.Left := Rec.Right; + Rec.Right := (Start+Length-Lines[NrLines].Line[Lines[NrLines].Current].Note[0].Start) * TempR + Left - NotesW - 0.5 + 10*ScreenX; glBindTexture(GL_TEXTURE_2D, Tex_plain_Mid[PlayerNumber].TexNum); glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT ); @@ -340,7 +328,7 @@ begin glEnd; // right part - Rec.Left := Rec.Right; + Rec.Left := Rec.Right; Rec.Right := Rec.Right + NotesW; glBindTexture(GL_TEXTURE_2D, Tex_plain_Right[PlayerNumber].TexNum); @@ -352,7 +340,7 @@ begin glEnd; // Golden Star Patch - if (NoteType = ntGolden) AND (Ini.EffectSing=1) then + if (NoteType = ntGolden) and (Ini.EffectSing=1) then begin GoldenRec.SaveGoldenStarsRec(GoldenStarPos, Rec.Top, Rec.Right, Rec.Bottom); end; @@ -366,22 +354,23 @@ begin glDisable(GL_TEXTURE_2D); end; - // draw sung notes procedure SingDrawPlayerLine(X, Y, W: real; PlayerIndex: integer; Space: integer); var TempR: real; Rec: TRecR; N: integer; - //R, G, B, A: real; +// R, G, B, A: real; NotesH2: real; begin //Log.LogStatus('Player notes', 'SingDraw'); - - //if NrGracza = 0 then LoadColor(R, G, B, 'P1Light') - //else LoadColor(R, G, B, 'P2Light'); - - //R := 71/255; +{ + if NrGracza = 0 then + LoadColor(R, G, B, 'P1Light') + else + LoadColor(R, G, B, 'P2Light'); +} + //R := 71/255; //G := 175/255; //B := 247/255; @@ -398,7 +387,7 @@ begin with Player[PlayerIndex].Note[N] do begin // Left part of note - Rec.Left := X + (Start-Lines[0].Line[Lines[0].Current].Note[0].Start) * TempR + 0.5 + 10*ScreenX; + Rec.Left := X + (Start-Lines[0].Line[Lines[0].Current].Note[0].Start) * TempR + 0.5 + 10*ScreenX; Rec.Right := Rec.Left + NotesW; // Draw it in half size, if not hit @@ -412,7 +401,7 @@ begin end; Rec.Top := Y - (Tone-Lines[0].Line[Lines[0].Current].BaseNote)*Space/2 - NotesH2; - Rec.Bottom := Rec.Top + 2 *NotesH2; + Rec.Bottom := Rec.Top + 2 * NotesH2; // draw the left part glColor3f(1, 1, 1); @@ -425,10 +414,10 @@ begin glEnd; // Middle part of the note - Rec.Left := Rec.Right; + Rec.Left := Rec.Right; Rec.Right := X + (Start+Length-Lines[0].Line[Lines[0].Current].Note[0].Start) * TempR - NotesW - 0.5 + 10*ScreenX; - // (nowe) - dunno + // new if (Start+Length-1 = LyricsState.CurrentBeatD) then Rec.Right := Rec.Right - (1-Frac(LyricsState.MidBeatD)) * TempR; // the left note is more right than the right note itself, sounds weird - so we fix that xD @@ -448,7 +437,7 @@ begin glColor3f(1, 1, 1); // the right part of the note - Rec.Left := Rec.Right; + Rec.Left := Rec.Right; Rec.Right := Rec.Right + NotesW; glBindTexture(GL_TEXTURE_2D, Tex_Right[PlayerIndex+1].TexNum); @@ -485,14 +474,12 @@ end; //draw Note glow procedure SingDrawPlayerBGLine(Left, Top, Right: real; NrLines, PlayerIndex: integer; Space: integer); var - Rec: TRecR; - Count: integer; - TempR: real; + Rec: TRecR; + Count: integer; + TempR: real; X1, X2, X3, X4: real; - W, H: real; - - lTmpA , - lTmpB : real; + W, H: real; + lTmpA, lTmpB: real; begin if (Player[PlayerIndex].ScoreTotalInt >= 0) then begin @@ -504,15 +491,10 @@ begin lTmpA := (Right-Left); lTmpB := (Lines[NrLines].Line[Lines[NrLines].Current].End_ - Lines[NrLines].Line[Lines[NrLines].Current].Note[0].Start); - if ( lTmpA > 0 ) and - ( lTmpB > 0 ) then - begin - TempR := lTmpA / lTmpB; - end + if ( lTmpA > 0 ) and ( lTmpB > 0 ) then + TempR := lTmpA / lTmpB else - begin TempR := 0; - end; with Lines[NrLines].Line[Lines[NrLines].Current] do begin @@ -527,14 +509,14 @@ begin W := NotesW * 2 + 2; H := NotesH * 1.5 + 3.5; - X2 := (Start-Lines[NrLines].Line[Lines[NrLines].Current].Note[0].Start) * TempR + Left + 0.5 + 10*ScreenX + 4; // wciecie + X2 := (Start-Lines[NrLines].Line[Lines[NrLines].Current].Note[0].Start) * TempR + Left + 0.5 + 10*ScreenX + 4; X1 := X2-W; - X3 := (Start+Length-Lines[NrLines].Line[Lines[NrLines].Current].Note[0].Start) * TempR + Left - 0.5 + 10*ScreenX - 4; // wciecie + X3 := (Start+Length-Lines[NrLines].Line[Lines[NrLines].Current].Note[0].Start) * TempR + Left - 0.5 + 10*ScreenX - 4; X4 := X3+W; // left - Rec.Left := X1; + Rec.Left := X1; Rec.Right := X2; Rec.Top := Top - (Tone-BaseNote)*Space/2 - H; Rec.Bottom := Rec.Top + 2 * H; @@ -547,8 +529,8 @@ begin glTexCoord2f(1, 0); glVertex2f(Rec.Right, Rec.Top); glEnd; - // srodkowa czesc - Rec.Left := X2; + // middle part + Rec.Left := X2; Rec.Right := X3; glBindTexture(GL_TEXTURE_2D, Tex_BG_Mid[PlayerIndex+1].TexNum); @@ -559,8 +541,8 @@ begin glTexCoord2f(1, 0); glVertex2f(Rec.Right, Rec.Top); glEnd; - // prawa czesc - Rec.Left := X3; + // right part + Rec.Left := X3; Rec.Right := X4; glBindTexture(GL_TEXTURE_2D, Tex_BG_Right[PlayerIndex+1].TexNum); @@ -608,7 +590,7 @@ begin // FIXME: accessing ScreenSing is not that generic LyricEngine := ScreenSing.Lyrics; - + // do not draw the lyrics helper if the current line does not contain any note if (Length(CurLine.Note) > 0) then begin @@ -696,27 +678,25 @@ begin // FIXME: accessing ScreenSing is not that generic LyricEngine := ScreenSing.Lyrics; - // background //BG Fullsize Mod - //SingDrawBackground; - // draw time-bar SingDrawTimeBar(); // draw note-lines if (PlayersPlay = 1) and (Ini.NoteLines = 1) then - SingDrawNoteLines(Nr.Left + 10*ScreenX, Skin_P2_NotesB - 105, Nr.Right + 10*ScreenX, 15); + SingDrawNoteLines(NR.Left + 10*ScreenX, Skin_P2_NotesB - 105, NR.Right + 10*ScreenX, 15); if ((PlayersPlay = 2) or (PlayersPlay = 4)) and (Ini.NoteLines = 1) then begin - SingDrawNoteLines(Nr.Left + 10*ScreenX, Skin_P1_NotesB - 105, Nr.Right + 10*ScreenX, 15); - SingDrawNoteLines(Nr.Left + 10*ScreenX, Skin_P2_NotesB - 105, Nr.Right + 10*ScreenX, 15); + SingDrawNoteLines(NR.Left + 10*ScreenX, Skin_P1_NotesB - 105, NR.Right + 10*ScreenX, 15); + SingDrawNoteLines(NR.Left + 10*ScreenX, Skin_P2_NotesB - 105, NR.Right + 10*ScreenX, 15); end; - if ((PlayersPlay = 3) or (PlayersPlay = 6)) and (Ini.NoteLines = 1) then begin - SingDrawNoteLines(Nr.Left + 10*ScreenX, 120, Nr.Right + 10*ScreenX, 12); - SingDrawNoteLines(Nr.Left + 10*ScreenX, 245, Nr.Right + 10*ScreenX, 12); - SingDrawNoteLines(Nr.Left + 10*ScreenX, 370, Nr.Right + 10*ScreenX, 12); + if ((PlayersPlay = 3) or (PlayersPlay = 6)) and (Ini.NoteLines = 1) then + begin + SingDrawNoteLines(NR.Left + 10*ScreenX, 120, NR.Right + 10*ScreenX, 12); + SingDrawNoteLines(NR.Left + 10*ScreenX, 245, NR.Right + 10*ScreenX, 12); + SingDrawNoteLines(NR.Left + 10*ScreenX, 370, NR.Right + 10*ScreenX, 12); end; // draw Lyrics @@ -724,39 +704,48 @@ begin SingDrawLyricHelper(NR.Left, NR.WMid); // oscilloscope - if Ini.Oscilloscope = 1 then begin + if Ini.Oscilloscope = 1 then + begin if PlayersPlay = 1 then SingDrawOscilloscope(190 + 10*ScreenX, 55, 180, 40, 0); - if PlayersPlay = 2 then begin + if PlayersPlay = 2 then + begin SingDrawOscilloscope(190 + 10*ScreenX, 55, 180, 40, 0); SingDrawOscilloscope(425 + 10*ScreenX, 55, 180, 40, 1); end; - if PlayersPlay = 4 then begin - if ScreenAct = 1 then begin + if PlayersPlay = 4 then + begin + if ScreenAct = 1 then + begin SingDrawOscilloscope(190 + 10*ScreenX, 55, 180, 40, 0); SingDrawOscilloscope(425 + 10*ScreenX, 55, 180, 40, 1); end; - if ScreenAct = 2 then begin + if ScreenAct = 2 then + begin SingDrawOscilloscope(190 + 10*ScreenX, 55, 180, 40, 2); SingDrawOscilloscope(425 + 10*ScreenX, 55, 180, 40, 3); end; end; - if PlayersPlay = 3 then begin - SingDrawOscilloscope(75 + 10*ScreenX, 95, 100, 20, 0); + if PlayersPlay = 3 then + begin + SingDrawOscilloscope( 75 + 10*ScreenX, 95, 100, 20, 0); SingDrawOscilloscope(370 + 10*ScreenX, 95, 100, 20, 1); SingDrawOscilloscope(670 + 10*ScreenX, 95, 100, 20, 2); end; - if PlayersPlay = 6 then begin - if ScreenAct = 1 then begin + if PlayersPlay = 6 then + begin + if ScreenAct = 1 then + begin SingDrawOscilloscope( 75 + 10*ScreenX, 95, 100, 20, 0); SingDrawOscilloscope(370 + 10*ScreenX, 95, 100, 20, 1); SingDrawOscilloscope(670 + 10*ScreenX, 95, 100, 20, 2); end; - if ScreenAct = 2 then begin + if ScreenAct = 2 then + begin SingDrawOscilloscope( 75 + 10*ScreenX, 95, 100, 20, 3); SingDrawOscilloscope(370 + 10*ScreenX, 95, 100, 20, 4); SingDrawOscilloscope(670 + 10*ScreenX, 95, 100, 20, 5); @@ -785,104 +774,121 @@ begin end; // Draw the Notes - if PlayersPlay = 1 then begin + if PlayersPlay = 1 then + begin SingDrawPlayerBGLine(NR.Left + 20, Skin_P2_NotesB, NR.Right - 20, 0, 0, 15); // Background glow - colorized in playercolor SingDrawLine(NR.Left + 20, Skin_P2_NotesB, NR.Right - 20, 0, 15); // Plain unsung notes - colorized in playercolor - SingDrawPlayerLine(Nr.Left + 20, Skin_P2_NotesB, Nr.Width - 40, 0, 15); // imho the sung notes + SingDrawPlayerLine(NR.Left + 20, Skin_P2_NotesB, NR.Width - 40, 0, 15); // imho the sung notes end; - if (PlayersPlay = 2) then begin - SingDrawPlayerBGLine(Nr.Left + 20, Skin_P1_NotesB, Nr.Right - 20, 0, 0, 15); - SingDrawPlayerBGLine(Nr.Left + 20, Skin_P2_NotesB, Nr.Right - 20, 0, 1, 15); + if PlayersPlay = 2 then + begin + SingDrawPlayerBGLine(NR.Left + 20, Skin_P1_NotesB, NR.Right - 20, 0, 0, 15); + SingDrawPlayerBGLine(NR.Left + 20, Skin_P2_NotesB, NR.Right - 20, 0, 1, 15); SingDrawLine(NR.Left + 20, Skin_P1_NotesB, NR.Right - 20, 0, 15); SingDrawLine(NR.Left + 20, Skin_P2_NotesB, NR.Right - 20, 1, 15); - SingDrawPlayerLine(Nr.Left + 20, Skin_P1_NotesB, Nr.Width - 40, 0, 15); - SingDrawPlayerLine(Nr.Left + 20, Skin_P2_NotesB, Nr.Width - 40, 1, 15); + SingDrawPlayerLine(NR.Left + 20, Skin_P1_NotesB, NR.Width - 40, 0, 15); + SingDrawPlayerLine(NR.Left + 20, Skin_P2_NotesB, NR.Width - 40, 1, 15); end; - if PlayersPlay = 3 then begin + if PlayersPlay = 3 then + begin NotesW := NotesW * 0.8; NotesH := NotesH * 0.8; - SingDrawPlayerBGLine(Nr.Left + 20, 120+95, Nr.Right - 20, 0, 0, 12); - SingDrawPlayerBGLine(Nr.Left + 20, 245+95, Nr.Right - 20, 0, 1, 12); - SingDrawPlayerBGLine(Nr.Left + 20, 370+95, Nr.Right - 20, 0, 2, 12); + SingDrawPlayerBGLine(NR.Left + 20, 120+95, NR.Right - 20, 0, 0, 12); + SingDrawPlayerBGLine(NR.Left + 20, 245+95, NR.Right - 20, 0, 1, 12); + SingDrawPlayerBGLine(NR.Left + 20, 370+95, NR.Right - 20, 0, 2, 12); SingDrawLine(NR.Left + 20, 120+95, NR.Right - 20, 0, 12); SingDrawLine(NR.Left + 20, 245+95, NR.Right - 20, 1, 12); SingDrawLine(NR.Left + 20, 370+95, NR.Right - 20, 2, 12); - SingDrawPlayerLine(Nr.Left + 20, 120+95, Nr.Width - 40, 0, 12); - SingDrawPlayerLine(Nr.Left + 20, 245+95, Nr.Width - 40, 1, 12); - SingDrawPlayerLine(Nr.Left + 20, 370+95, Nr.Width - 40, 2, 12); + SingDrawPlayerLine(NR.Left + 20, 120+95, NR.Width - 40, 0, 12); + SingDrawPlayerLine(NR.Left + 20, 245+95, NR.Width - 40, 1, 12); + SingDrawPlayerLine(NR.Left + 20, 370+95, NR.Width - 40, 2, 12); end; - if PlayersPlay = 4 then begin - if ScreenAct = 1 then begin - SingDrawPlayerBGLine(Nr.Left + 20, Skin_P1_NotesB, Nr.Right - 20, 0, 0, 15); - SingDrawPlayerBGLine(Nr.Left + 20, Skin_P2_NotesB, Nr.Right - 20, 0, 1, 15); + if PlayersPlay = 4 then + begin + if ScreenAct = 1 then + begin + SingDrawPlayerBGLine(NR.Left + 20, Skin_P1_NotesB, NR.Right - 20, 0, 0, 15); + SingDrawPlayerBGLine(NR.Left + 20, Skin_P2_NotesB, NR.Right - 20, 0, 1, 15); end; - if ScreenAct = 2 then begin - SingDrawPlayerBGLine(Nr.Left + 20, Skin_P1_NotesB, Nr.Right - 20, 0, 2, 15); - SingDrawPlayerBGLine(Nr.Left + 20, Skin_P2_NotesB, Nr.Right - 20, 0, 3, 15); + if ScreenAct = 2 then + begin + SingDrawPlayerBGLine(NR.Left + 20, Skin_P1_NotesB, NR.Right - 20, 0, 2, 15); + SingDrawPlayerBGLine(NR.Left + 20, Skin_P2_NotesB, NR.Right - 20, 0, 3, 15); end; - if ScreenAct = 1 then begin + if ScreenAct = 1 then + begin SingDrawLine(NR.Left + 20, Skin_P1_NotesB, NR.Right - 20, 0, 15); SingDrawLine(NR.Left + 20, Skin_P2_NotesB, NR.Right - 20, 1, 15); end; - if ScreenAct = 2 then begin + if ScreenAct = 2 then + begin SingDrawLine(NR.Left + 20, Skin_P1_NotesB, NR.Right - 20, 2, 15); SingDrawLine(NR.Left + 20, Skin_P2_NotesB, NR.Right - 20, 3, 15); end; - if ScreenAct = 1 then begin - SingDrawPlayerLine(Nr.Left + 20, Skin_P1_NotesB, Nr.Width - 40, 0, 15); - SingDrawPlayerLine(Nr.Left + 20, Skin_P2_NotesB, Nr.Width - 40, 1, 15); + if ScreenAct = 1 then + begin + SingDrawPlayerLine(NR.Left + 20, Skin_P1_NotesB, NR.Width - 40, 0, 15); + SingDrawPlayerLine(NR.Left + 20, Skin_P2_NotesB, NR.Width - 40, 1, 15); end; - if ScreenAct = 2 then begin - SingDrawPlayerLine(Nr.Left + 20, Skin_P1_NotesB, Nr.Width - 40, 2, 15); - SingDrawPlayerLine(Nr.Left + 20, Skin_P2_NotesB, Nr.Width - 40, 3, 15); + if ScreenAct = 2 then + begin + SingDrawPlayerLine(NR.Left + 20, Skin_P1_NotesB, NR.Width - 40, 2, 15); + SingDrawPlayerLine(NR.Left + 20, Skin_P2_NotesB, NR.Width - 40, 3, 15); end; end; - if PlayersPlay = 6 then begin + if PlayersPlay = 6 then + begin NotesW := NotesW * 0.8; NotesH := NotesH * 0.8; - if ScreenAct = 1 then begin - SingDrawPlayerBGLine(Nr.Left + 20, 120+95, Nr.Right - 20, 0, 0, 12); - SingDrawPlayerBGLine(Nr.Left + 20, 245+95, Nr.Right - 20, 0, 1, 12); - SingDrawPlayerBGLine(Nr.Left + 20, 370+95, Nr.Right - 20, 0, 2, 12); + if ScreenAct = 1 then + begin + SingDrawPlayerBGLine(NR.Left + 20, 120+95, NR.Right - 20, 0, 0, 12); + SingDrawPlayerBGLine(NR.Left + 20, 245+95, NR.Right - 20, 0, 1, 12); + SingDrawPlayerBGLine(NR.Left + 20, 370+95, NR.Right - 20, 0, 2, 12); end; - if ScreenAct = 2 then begin - SingDrawPlayerBGLine(Nr.Left + 20, 120+95, Nr.Right - 20, 0, 3, 12); - SingDrawPlayerBGLine(Nr.Left + 20, 245+95, Nr.Right - 20, 0, 4, 12); - SingDrawPlayerBGLine(Nr.Left + 20, 370+95, Nr.Right - 20, 0, 5, 12); + if ScreenAct = 2 then + begin + SingDrawPlayerBGLine(NR.Left + 20, 120+95, NR.Right - 20, 0, 3, 12); + SingDrawPlayerBGLine(NR.Left + 20, 245+95, NR.Right - 20, 0, 4, 12); + SingDrawPlayerBGLine(NR.Left + 20, 370+95, NR.Right - 20, 0, 5, 12); end; - if ScreenAct = 1 then begin + if ScreenAct = 1 then + begin SingDrawLine(NR.Left + 20, 120+95, NR.Right - 20, 0, 12); SingDrawLine(NR.Left + 20, 245+95, NR.Right - 20, 1, 12); SingDrawLine(NR.Left + 20, 370+95, NR.Right - 20, 2, 12); end; - if ScreenAct = 2 then begin + if ScreenAct = 2 then + begin SingDrawLine(NR.Left + 20, 120+95, NR.Right - 20, 3, 12); SingDrawLine(NR.Left + 20, 245+95, NR.Right - 20, 4, 12); SingDrawLine(NR.Left + 20, 370+95, NR.Right - 20, 5, 12); end; - if ScreenAct = 1 then begin - SingDrawPlayerLine(Nr.Left + 20, 120+95, Nr.Width - 40, 0, 12); - SingDrawPlayerLine(Nr.Left + 20, 245+95, Nr.Width - 40, 1, 12); - SingDrawPlayerLine(Nr.Left + 20, 370+95, Nr.Width - 40, 2, 12); + if ScreenAct = 1 then + begin + SingDrawPlayerLine(NR.Left + 20, 120+95, NR.Width - 40, 0, 12); + SingDrawPlayerLine(NR.Left + 20, 245+95, NR.Width - 40, 1, 12); + SingDrawPlayerLine(NR.Left + 20, 370+95, NR.Width - 40, 2, 12); end; - if ScreenAct = 2 then begin - SingDrawPlayerLine(Nr.Left + 20, 120+95, Nr.Width - 40, 3, 12); - SingDrawPlayerLine(Nr.Left + 20, 245+95, Nr.Width - 40, 4, 12); - SingDrawPlayerLine(Nr.Left + 20, 370+95, Nr.Width - 40, 5, 12); + if ScreenAct = 2 then + begin + SingDrawPlayerLine(NR.Left + 20, 120+95, NR.Width - 40, 3, 12); + SingDrawPlayerLine(NR.Left + 20, 245+95, NR.Width - 40, 4, 12); + SingDrawPlayerLine(NR.Left + 20, 370+95, NR.Width - 40, 5, 12); end; end; glDisable(GL_BLEND); @@ -892,12 +898,15 @@ end; // q'n'd for using the game mode dll's procedure SingModiDraw (PlayerInfo: TPlayerInfo); var - NR: TRecR; + NR: TRecR; begin // positions - if Ini.SingWindow = 0 then begin + if Ini.SingWindow = 0 then + begin NR.Left := 120; - end else begin + end + else + begin NR.Left := 20; end; @@ -912,16 +921,18 @@ begin if DLLMan.Selected.ShowNotes then begin if PlayersPlay = 1 then - SingDrawNoteLines(Nr.Left + 10*ScreenX, Skin_P2_NotesB - 105, Nr.Right + 10*ScreenX, 15); - if (PlayersPlay = 2) or (PlayersPlay = 4) then begin - SingDrawNoteLines(Nr.Left + 10*ScreenX, Skin_P1_NotesB - 105, Nr.Right + 10*ScreenX, 15); - SingDrawNoteLines(Nr.Left + 10*ScreenX, Skin_P2_NotesB - 105, Nr.Right + 10*ScreenX, 15); + SingDrawNoteLines(NR.Left + 10*ScreenX, Skin_P2_NotesB - 105, NR.Right + 10*ScreenX, 15); + if (PlayersPlay = 2) or (PlayersPlay = 4) then + begin + SingDrawNoteLines(NR.Left + 10*ScreenX, Skin_P1_NotesB - 105, NR.Right + 10*ScreenX, 15); + SingDrawNoteLines(NR.Left + 10*ScreenX, Skin_P2_NotesB - 105, NR.Right + 10*ScreenX, 15); end; - if (PlayersPlay = 3) or (PlayersPlay = 6) then begin - SingDrawNoteLines(Nr.Left + 10*ScreenX, 120, Nr.Right + 10*ScreenX, 12); - SingDrawNoteLines(Nr.Left + 10*ScreenX, 245, Nr.Right + 10*ScreenX, 12); - SingDrawNoteLines(Nr.Left + 10*ScreenX, 370, Nr.Right + 10*ScreenX, 12); + if (PlayersPlay = 3) or (PlayersPlay = 6) then + begin + SingDrawNoteLines(NR.Left + 10*ScreenX, 120, NR.Right + 10*ScreenX, 12); + SingDrawNoteLines(NR.Left + 10*ScreenX, 245, NR.Right + 10*ScreenX, 12); + SingDrawNoteLines(NR.Left + 10*ScreenX, 370, NR.Right + 10*ScreenX, 12); end; end; @@ -930,26 +941,31 @@ begin // TODO: Lyrics helper // oscilloscope | the thing that moves when you yell into your mic (imho) - if (((Ini.Oscilloscope = 1) AND (DLLMan.Selected.ShowRateBar_O)) AND (NOT DLLMan.Selected.ShowRateBar)) then begin + if (((Ini.Oscilloscope = 1) and (DLLMan.Selected.ShowRateBar_O)) and (not DLLMan.Selected.ShowRateBar)) then + begin if PlayersPlay = 1 then if PlayerInfo.Playerinfo[0].Enabled then SingDrawOscilloscope(190 + 10*ScreenX, 55, 180, 40, 0); - if PlayersPlay = 2 then begin + if PlayersPlay = 2 then + begin if PlayerInfo.Playerinfo[0].Enabled then SingDrawOscilloscope(190 + 10*ScreenX, 55, 180, 40, 0); if PlayerInfo.Playerinfo[1].Enabled then SingDrawOscilloscope(425 + 10*ScreenX, 55, 180, 40, 1); end; - if PlayersPlay = 4 then begin - if ScreenAct = 1 then begin + if PlayersPlay = 4 then + begin + if ScreenAct = 1 then + begin if PlayerInfo.Playerinfo[0].Enabled then SingDrawOscilloscope(190 + 10*ScreenX, 55, 180, 40, 0); if PlayerInfo.Playerinfo[1].Enabled then SingDrawOscilloscope(425 + 10*ScreenX, 55, 180, 40, 1); end; - if ScreenAct = 2 then begin + if ScreenAct = 2 then + begin if PlayerInfo.Playerinfo[2].Enabled then SingDrawOscilloscope(190 + 10*ScreenX, 55, 180, 40, 2); if PlayerInfo.Playerinfo[3].Enabled then @@ -957,17 +973,20 @@ begin end; end; - if PlayersPlay = 3 then begin + if PlayersPlay = 3 then + begin if PlayerInfo.Playerinfo[0].Enabled then - SingDrawOscilloscope(75 + 10*ScreenX, 95, 100, 20, 0); + SingDrawOscilloscope( 75 + 10*ScreenX, 95, 100, 20, 0); if PlayerInfo.Playerinfo[1].Enabled then SingDrawOscilloscope(370 + 10*ScreenX, 95, 100, 20, 1); if PlayerInfo.Playerinfo[2].Enabled then SingDrawOscilloscope(670 + 10*ScreenX, 95, 100, 20, 2); end; - if PlayersPlay = 6 then begin - if ScreenAct = 1 then begin + if PlayersPlay = 6 then + begin + if ScreenAct = 1 then + begin if PlayerInfo.Playerinfo[0].Enabled then SingDrawOscilloscope( 75 + 10*ScreenX, 95, 100, 20, 0); if PlayerInfo.Playerinfo[1].Enabled then @@ -975,7 +994,8 @@ begin if PlayerInfo.Playerinfo[2].Enabled then SingDrawOscilloscope(670 + 10*ScreenX, 95, 100, 20, 2); end; - if ScreenAct = 2 then begin + if ScreenAct = 2 then + begin if PlayerInfo.Playerinfo[3].Enabled then SingDrawOscilloscope( 75 + 10*ScreenX, 95, 100, 20, 3); if PlayerInfo.Playerinfo[4].Enabled then @@ -1006,107 +1026,120 @@ begin end; end; - if (DLLMAn.Selected.ShowNotes And DLLMan.Selected.LoadSong) then + if (DLLMAn.Selected.ShowNotes and DLLMan.Selected.LoadSong) then begin - if (PlayersPlay = 1) And PlayerInfo.Playerinfo[0].Enabled then begin + if (PlayersPlay = 1) and PlayerInfo.Playerinfo[0].Enabled then + begin SingDrawPlayerBGLine(NR.Left + 20, Skin_P2_NotesB, NR.Right - 20, 0, 0, 15); SingDrawLine(NR.Left + 20, Skin_P2_NotesB, NR.Right - 20, 0, 15); - SingDrawPlayerLine(Nr.Left + 20, Skin_P2_NotesB, Nr.Width - 40, 0, 15); + SingDrawPlayerLine(NR.Left + 20, Skin_P2_NotesB, NR.Width - 40, 0, 15); end; - if (PlayersPlay = 2) then begin + if PlayersPlay = 2 then + begin if PlayerInfo.Playerinfo[0].Enabled then begin - SingDrawPlayerBGLine(Nr.Left + 20, Skin_P1_NotesB, Nr.Right - 20, 0, 0, 15); + SingDrawPlayerBGLine(NR.Left + 20, Skin_P1_NotesB, NR.Right - 20, 0, 0, 15); SingDrawLine(NR.Left + 20, Skin_P1_NotesB, NR.Right - 20, 0, 15); - SingDrawPlayerLine(Nr.Left + 20, Skin_P1_NotesB, Nr.Width - 40, 0, 15); + SingDrawPlayerLine(NR.Left + 20, Skin_P1_NotesB, NR.Width - 40, 0, 15); end; if PlayerInfo.Playerinfo[1].Enabled then begin - SingDrawPlayerBGLine(Nr.Left + 20, Skin_P2_NotesB, Nr.Right - 20, 0, 1, 15); + SingDrawPlayerBGLine(NR.Left + 20, Skin_P2_NotesB, NR.Right - 20, 0, 1, 15); SingDrawLine(NR.Left + 20, Skin_P2_NotesB, NR.Right - 20, 0, 15); - SingDrawPlayerLine(Nr.Left + 20, Skin_P2_NotesB, Nr.Width - 40, 1, 15); + SingDrawPlayerLine(NR.Left + 20, Skin_P2_NotesB, NR.Width - 40, 1, 15); end; end; - if PlayersPlay = 3 then begin + if PlayersPlay = 3 then + begin NotesW := NotesW * 0.8; NotesH := NotesH * 0.8; if PlayerInfo.Playerinfo[0].Enabled then begin - SingDrawPlayerBGLine(Nr.Left + 20, 120+95, Nr.Right - 20, 0, 0, 12); + SingDrawPlayerBGLine(NR.Left + 20, 120+95, NR.Right - 20, 0, 0, 12); SingDrawLine(NR.Left + 20, 120+95, NR.Right - 20, 0, 12); - SingDrawPlayerLine(Nr.Left + 20, 120+95, Nr.Width - 40, 0, 12); + SingDrawPlayerLine(NR.Left + 20, 120+95, NR.Width - 40, 0, 12); end; if PlayerInfo.Playerinfo[1].Enabled then begin - SingDrawPlayerBGLine(Nr.Left + 20, 245+95, Nr.Right - 20, 0, 1, 12); + SingDrawPlayerBGLine(NR.Left + 20, 245+95, NR.Right - 20, 0, 1, 12); SingDrawLine(NR.Left + 20, 245+95, NR.Right - 20, 0, 12); - SingDrawPlayerLine(Nr.Left + 20, 245+95, Nr.Width - 40, 1, 12); + SingDrawPlayerLine(NR.Left + 20, 245+95, NR.Width - 40, 1, 12); end; if PlayerInfo.Playerinfo[2].Enabled then begin - SingDrawPlayerBGLine(Nr.Left + 20, 370+95, Nr.Right - 20, 0, 2, 12); + SingDrawPlayerBGLine(NR.Left + 20, 370+95, NR.Right - 20, 0, 2, 12); SingDrawLine(NR.Left + 20, 370+95, NR.Right - 20, 0, 12); - SingDrawPlayerLine(Nr.Left + 20, 370+95, Nr.Width - 40, 2, 12); + SingDrawPlayerLine(NR.Left + 20, 370+95, NR.Width - 40, 2, 12); end; end; - if PlayersPlay = 4 then begin - if ScreenAct = 1 then begin - SingDrawPlayerBGLine(Nr.Left + 20, Skin_P1_NotesB, Nr.Right - 20, 0, 0, 15); - SingDrawPlayerBGLine(Nr.Left + 20, Skin_P2_NotesB, Nr.Right - 20, 0, 1, 15); + if PlayersPlay = 4 then + begin + if ScreenAct = 1 then + begin + SingDrawPlayerBGLine(NR.Left + 20, Skin_P1_NotesB, NR.Right - 20, 0, 0, 15); + SingDrawPlayerBGLine(NR.Left + 20, Skin_P2_NotesB, NR.Right - 20, 0, 1, 15); end; - if ScreenAct = 2 then begin - SingDrawPlayerBGLine(Nr.Left + 20, Skin_P1_NotesB, Nr.Right - 20, 0, 2, 15); - SingDrawPlayerBGLine(Nr.Left + 20, Skin_P2_NotesB, Nr.Right - 20, 0, 3, 15); + if ScreenAct = 2 then + begin + SingDrawPlayerBGLine(NR.Left + 20, Skin_P1_NotesB, NR.Right - 20, 0, 2, 15); + SingDrawPlayerBGLine(NR.Left + 20, Skin_P2_NotesB, NR.Right - 20, 0, 3, 15); end; SingDrawLine(NR.Left + 20, Skin_P1_NotesB, NR.Right - 20, 0, 15); SingDrawLine(NR.Left + 20, Skin_P2_NotesB, NR.Right - 20, 0, 15); - if ScreenAct = 1 then begin - SingDrawPlayerLine(Nr.Left + 20, Skin_P1_NotesB, Nr.Width - 40, 0, 15); - SingDrawPlayerLine(Nr.Left + 20, Skin_P2_NotesB, Nr.Width - 40, 1, 15); + if ScreenAct = 1 then + begin + SingDrawPlayerLine(NR.Left + 20, Skin_P1_NotesB, NR.Width - 40, 0, 15); + SingDrawPlayerLine(NR.Left + 20, Skin_P2_NotesB, NR.Width - 40, 1, 15); end; - if ScreenAct = 2 then begin - SingDrawPlayerLine(Nr.Left + 20, Skin_P1_NotesB, Nr.Width - 40, 2, 15); - SingDrawPlayerLine(Nr.Left + 20, Skin_P2_NotesB, Nr.Width - 40, 3, 15); + if ScreenAct = 2 then + begin + SingDrawPlayerLine(NR.Left + 20, Skin_P1_NotesB, NR.Width - 40, 2, 15); + SingDrawPlayerLine(NR.Left + 20, Skin_P2_NotesB, NR.Width - 40, 3, 15); end; end; - if PlayersPlay = 6 then begin + if PlayersPlay = 6 then + begin NotesW := NotesW * 0.8; NotesH := NotesH * 0.8; - if ScreenAct = 1 then begin - SingDrawPlayerBGLine(Nr.Left + 20, 120+95, Nr.Right - 20, 0, 0, 12); - SingDrawPlayerBGLine(Nr.Left + 20, 245+95, Nr.Right - 20, 0, 1, 12); - SingDrawPlayerBGLine(Nr.Left + 20, 370+95, Nr.Right - 20, 0, 2, 12); + if ScreenAct = 1 then + begin + SingDrawPlayerBGLine(NR.Left + 20, 120+95, NR.Right - 20, 0, 0, 12); + SingDrawPlayerBGLine(NR.Left + 20, 245+95, NR.Right - 20, 0, 1, 12); + SingDrawPlayerBGLine(NR.Left + 20, 370+95, NR.Right - 20, 0, 2, 12); end; - if ScreenAct = 2 then begin - SingDrawPlayerBGLine(Nr.Left + 20, 120+95, Nr.Right - 20, 0, 3, 12); - SingDrawPlayerBGLine(Nr.Left + 20, 245+95, Nr.Right - 20, 0, 4, 12); - SingDrawPlayerBGLine(Nr.Left + 20, 370+95, Nr.Right - 20, 0, 5, 12); + if ScreenAct = 2 then + begin + SingDrawPlayerBGLine(NR.Left + 20, 120+95, NR.Right - 20, 0, 3, 12); + SingDrawPlayerBGLine(NR.Left + 20, 245+95, NR.Right - 20, 0, 4, 12); + SingDrawPlayerBGLine(NR.Left + 20, 370+95, NR.Right - 20, 0, 5, 12); end; SingDrawLine(NR.Left + 20, 120+95, NR.Right - 20, 0, 12); SingDrawLine(NR.Left + 20, 245+95, NR.Right - 20, 0, 12); SingDrawLine(NR.Left + 20, 370+95, NR.Right - 20, 0, 12); - if ScreenAct = 1 then begin - SingDrawPlayerLine(Nr.Left + 20, 120+95, Nr.Width - 40, 0, 12); - SingDrawPlayerLine(Nr.Left + 20, 245+95, Nr.Width - 40, 1, 12); - SingDrawPlayerLine(Nr.Left + 20, 370+95, Nr.Width - 40, 2, 12); + if ScreenAct = 1 then + begin + SingDrawPlayerLine(NR.Left + 20, 120+95, NR.Width - 40, 0, 12); + SingDrawPlayerLine(NR.Left + 20, 245+95, NR.Width - 40, 1, 12); + SingDrawPlayerLine(NR.Left + 20, 370+95, NR.Width - 40, 2, 12); end; - if ScreenAct = 2 then begin - SingDrawPlayerLine(Nr.Left + 20, 120+95, Nr.Width - 40, 3, 12); - SingDrawPlayerLine(Nr.Left + 20, 245+95, Nr.Width - 40, 4, 12); - SingDrawPlayerLine(Nr.Left + 20, 370+95, Nr.Width - 40, 5, 12); + if ScreenAct = 2 then + begin + SingDrawPlayerLine(NR.Left + 20, 120+95, NR.Width - 40, 3, 12); + SingDrawPlayerLine(NR.Left + 20, 245+95, NR.Width - 40, 4, 12); + SingDrawPlayerLine(NR.Left + 20, 370+95, NR.Width - 40, 5, 12); end; end; end; @@ -1115,15 +1148,14 @@ begin glDisable(GL_TEXTURE_2D); end; - {//SingBar Mod procedure SingDrawSingbar(X, Y, W, H: real; Percent: integer); var - R: Real; - G: Real; - B: Real; - A: cardinal; - I: Integer; + R: real; + G: real; + B: real; + A: cardinal; + I: integer; begin; @@ -1141,7 +1173,7 @@ begin; glEnd; //SingBar coloured Bar - Case Percent of + case Percent of 0..22: begin R := 1; G := 0; @@ -1167,7 +1199,7 @@ begin; G := 1; B := 0; end; - End; //Case + end; //case glColor4f(R, G, B, 1); glEnable(GL_TEXTURE_2D); @@ -1198,99 +1230,103 @@ end; //end Singbar Mod //PhrasenBonus - Line Bonus Pop Up -procedure SingDrawLineBonus( const X, Y: Single; Color: TRGB; Alpha: Single; Text: string; Age: Integer); +procedure SingDrawLineBonus(const X, Y: Single; Color: TRGB; Alpha: Single; Text: string; Age: integer); var -Length, X2: Real; //Length of Text -Size: Integer; //Size of Popup -begin -if Alpha <> 0 then + Length, X2: real; //Length of Text + Size: integer; //Size of Popup begin + if Alpha <> 0 then + begin //Set Font Propertys -SetFontStyle(2); //Font: Outlined1 -if Age < 5 then SetFontSize((Age + 1) * 3) else SetFontSize(18); -SetFontItalic(False); + SetFontStyle(2); //Font: Outlined1 + if Age < 5 then + SetFontSize((Age + 1) * 3) + else + SetFontSize(18); + SetFontItalic(False); //Check Font Size -Length := glTextWidth (Text) + 3; //Little Space for a Better Look ^^ + Length := glTextWidth (Text) + 3; //Little Space for a Better Look ^^ //Text -SetFontPos (X + 50 - (Length / 2), Y + 12); //Position + SetFontPos (X + 50 - (Length / 2), Y + 12); //Position + if Age < 5 then + Size := Age * 10 + else + Size := 50; -if Age < 5 then Size := Age * 10 else Size := 50; - - //Draw Background - //glColor4f(Color.R, Color.G, Color.B, Alpha); //Set Color - glColor4f(1, 1, 1, Alpha); - - - glEnable(GL_TEXTURE_2D); - glEnable(GL_BLEND); - //glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - +//Draw Background +// glColor4f(Color.R, Color.G, Color.B, Alpha); //Set Color + glColor4f(1, 1, 1, Alpha); - //New Method, Not Variable - glBindTexture(GL_TEXTURE_2D, Tex_SingLineBonusBack[2].TexNum); + glEnable(GL_TEXTURE_2D); + glEnable(GL_BLEND); +// glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - glBegin(GL_QUADS); - glTexCoord2f(0, 0); glVertex2f(X + 50 - Size, Y + 25 - (Size/2)); - glTexCoord2f(0, 1); glVertex2f(X + 50 - Size, Y + 25 + (Size/2)); - glTexCoord2f(1, 1); glVertex2f(X + 50 + Size, Y + 25 + (Size/2)); - glTexCoord2f(1, 0); glVertex2f(X + 50 + Size, Y + 25 - (Size/2)); - glEnd; +//New Method, Not Variable + glBindTexture(GL_TEXTURE_2D, Tex_SingLineBonusBack[2].TexNum); - glColor4f(1, 1, 1, Alpha); //Set Color - //Draw Text - glPrint (Text); -end; + glBegin(GL_QUADS); + glTexCoord2f(0, 0); glVertex2f(X + 50 - Size, Y + 25 - (Size/2)); + glTexCoord2f(0, 1); glVertex2f(X + 50 - Size, Y + 25 + (Size/2)); + glTexCoord2f(1, 1); glVertex2f(X + 50 + Size, Y + 25 + (Size/2)); + glTexCoord2f(1, 0); glVertex2f(X + 50 + Size, Y + 25 - (Size/2)); + glEnd; + + glColor4f(1, 1, 1, Alpha); //Set Color +//Draw Text + glPrint (Text); + end; end; //PhrasenBonus - Line Bonus Mod} // Draw Note Bars for Editor -//There are 11 Resons for a new Procdedure: (nice binary :D ) -// 1. It don't look good when you Draw the Golden Note Star Effect in the Editor -// 2. You can see the Freestyle Notes in the Editor SemiTransparent -// 3. Its easier and Faster then changing the old Procedure +// There are 11 reasons for a new procedure: (nice binary :D ) +// 1. It does not look good when you draw the golden note star effect in the editor +// 2. You can see the freestyle notes in the editor semitransparent +// 3. It is easier and faster then changing the old procedure procedure EditDrawLine(Left, Top, Right: real; NrLines: integer; Space: integer); var - Rec: TRecR; - Count: integer; - TempR: real; + Rec: TRecR; + Count: integer; + TempR: real; begin glColor3f(1, 1, 1); glEnable(GL_TEXTURE_2D); glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); TempR := (Right-Left) / (Lines[NrLines].Line[Lines[NrLines].Current].End_ - Lines[NrLines].Line[Lines[NrLines].Current].Note[0].Start); - with Lines[NrLines].Line[Lines[NrLines].Current] do begin - for Count := 0 to HighNote do begin - with Note[Count] do begin - - // Golden Note Patch - case NoteType of - ntFreestyle: glColor4f(1, 1, 1, 0.35); - ntNormal: glColor4f(1, 1, 1, 0.85); - ntGolden: Glcolor4f(1, 1, 0.3, 0.85); - end; // case - + with Lines[NrLines].Line[Lines[NrLines].Current] do + begin + for Count := 0 to HighNote do + begin + with Note[Count] do + begin + // Golden Note Patch + case NoteType of + ntFreestyle: glColor4f(1, 1, 1, 0.35); + ntNormal: glColor4f(1, 1, 1, 0.85); + ntGolden: Glcolor4f(1, 1, 0.3, 0.85); + end; // case - // lewa czesc - left part - Rec.Left := (Start-Lines[NrLines].Line[Lines[NrLines].Current].Note[0].Start) * TempR + Left + 0.5 + 10*ScreenX; - Rec.Right := Rec.Left + NotesW; - Rec.Top := Top - (Tone-BaseNote)*Space/2 - NotesH; - Rec.Bottom := Rec.Top + 2 * NotesH; - glBindTexture(GL_TEXTURE_2D, Tex_Left[Color].TexNum); - glBegin(GL_QUADS); - glTexCoord2f(0, 0); glVertex2f(Rec.Left, Rec.Top); - glTexCoord2f(0, 1); glVertex2f(Rec.Left, Rec.Bottom); - glTexCoord2f(1, 1); glVertex2f(Rec.Right, Rec.Bottom); - glTexCoord2f(1, 0); glVertex2f(Rec.Right, Rec.Top); - glEnd; + // left part + Rec.Left := (Start-Lines[NrLines].Line[Lines[NrLines].Current].Note[0].Start) * TempR + Left + 0.5 + 10*ScreenX; + Rec.Right := Rec.Left + NotesW; + Rec.Top := Top - (Tone-BaseNote)*Space/2 - NotesH; + Rec.Bottom := Rec.Top + 2 * NotesH; + glBindTexture(GL_TEXTURE_2D, Tex_Left[Color].TexNum); + glBegin(GL_QUADS); + glTexCoord2f(0, 0); glVertex2f(Rec.Left, Rec.Top); + glTexCoord2f(0, 1); glVertex2f(Rec.Left, Rec.Bottom); + glTexCoord2f(1, 1); glVertex2f(Rec.Right, Rec.Bottom); + glTexCoord2f(1, 0); glVertex2f(Rec.Right, Rec.Top); + glEnd; - // srodkowa czesc - middle part - Rec.Left := Rec.Right; + // middle part + Rec.Left := Rec.Right; Rec.Right := (Start+Length-Lines[NrLines].Line[Lines[NrLines].Current].Note[0].Start) * TempR + Left - NotesW - 0.5 + 10*ScreenX; glBindTexture(GL_TEXTURE_2D, Tex_Mid[Color].TexNum); @@ -1301,8 +1337,8 @@ begin glTexCoord2f(1, 0); glVertex2f(Rec.Right, Rec.Top); glEnd; - // prawa czesc - right part - Rec.Left := Rec.Right; + // right part + Rec.Left := Rec.Right; Rec.Right := Rec.Right + NotesW; glBindTexture(GL_TEXTURE_2D, Tex_Right[Color].TexNum); @@ -1323,7 +1359,7 @@ end; procedure SingDrawTimeBar(); var - x,y: real; + x, y: real; width, height: real; LyricsProgress: real; CurLyricsTime: real; diff --git a/unicode/src/base/UEditorLyrics.pas b/unicode/src/base/UEditorLyrics.pas index d06fc891..fe8c3ee5 100644 --- a/unicode/src/base/UEditorLyrics.pas +++ b/unicode/src/base/UEditorLyrics.pas @@ -40,48 +40,50 @@ uses UTexture; type + alignment = (left, center, right); + TWord = record - X: real; - Y: real; - Size: real; - Width: real; - Text: string; - ColR: real; - ColG: real; - ColB: real; - FontStyle: integer; - Italic: boolean; - Selected: boolean; + X: real; + Y: real; + Size: real; + Width: real; + Text: string; + ColR: real; + ColG: real; + ColB: real; + FontStyle: integer; + Italic: boolean; + Selected: boolean; end; TEditorLyrics = class private - AlignI: integer; - XR: real; - YR: real; - SizeR: real; - SelectedI: integer; - FontStyleI: integer; // font number - Word: array of TWord; + AlignI: alignment; + XR: real; + YR: real; + SizeR: real; + SelectedI: integer; + FontStyleI: integer; // font number + Word: array of TWord; procedure SetX(Value: real); procedure SetY(Value: real); function GetClientX: real; - procedure SetAlign(Value: integer); + procedure SetAlign(Value: alignment); function GetSize: real; procedure SetSize(Value: real); procedure SetSelected(Value: integer); - procedure SetFStyle(Value: integer); + procedure SetFontStyle(Value: integer); procedure AddWord(Text: string); procedure Refresh; public - ColR: real; - ColG: real; - ColB: real; - ColSR: real; - ColSG: real; - ColSB: real; - Italic: boolean; + ColR: real; + ColG: real; + ColB: real; + ColSR: real; + ColSG: real; + ColSB: real; + Italic: boolean; constructor Create; destructor Destroy; override; @@ -94,16 +96,20 @@ type property X: real write SetX; property Y: real write SetY; property ClientX: real read GetClientX; - property Align: integer write SetAlign; + property Align: alignment write SetAlign; property Size: real read GetSize write SetSize; property Selected: integer read SelectedI write SetSelected; - property FontStyle: integer write SetFStyle; + property FontStyle: integer write SetFontStyle; end; implementation uses - TextGL, UGraphic, UDrawTexture, Math, USkins; + TextGL, + UGraphic, + UDrawTexture, + Math, + USkins; constructor TEditorLyrics.Create; begin @@ -131,7 +137,7 @@ begin Result := Word[0].X; end; -procedure TEditorLyrics.SetAlign(Value: integer); +procedure TEditorLyrics.SetAlign(Value: alignment); begin AlignI := Value; end; @@ -148,7 +154,7 @@ end; procedure TEditorLyrics.SetSelected(Value: integer); begin - if (SelectedI > -1) and (SelectedI <= High(Word)) then + if (-1 < SelectedI) and (SelectedI <= High(Word)) then begin Word[SelectedI].Selected := false; Word[SelectedI].ColR := ColR; @@ -157,7 +163,7 @@ begin end; SelectedI := Value; - if (Value > -1) and (Value <= High(Word)) then + if (-1 < Value) and (Value <= High(Word)) then begin Word[Value].Selected := true; Word[Value].ColR := ColSR; @@ -168,22 +174,21 @@ begin Refresh; end; -procedure TEditorLyrics.SetFStyle(Value: integer); +procedure TEditorLyrics.SetFontStyle(Value: integer); begin FontStyleI := Value; end; procedure TEditorLyrics.AddWord(Text: string); var - WordNum: integer; + WordNum: integer; begin WordNum := Length(Word); SetLength(Word, WordNum + 1); - if WordNum = 0 then begin - Word[WordNum].X := XR; - end else begin + if WordNum = 0 then + Word[WordNum].X := XR + else Word[WordNum].X := Word[WordNum - 1].X + Word[WordNum - 1].Width; - end; Word[WordNum].Y := YR; Word[WordNum].Size := SizeR; @@ -202,12 +207,13 @@ end; procedure TEditorLyrics.AddLine(NrLine: integer); var - N: integer; + NoteIndex: integer; begin Clear; - for N := 0 to Lines[0].Line[NrLine].HighNote do begin - Italic := Lines[0].Line[NrLine].Note[N].NoteType = ntFreestyle; - AddWord(Lines[0].Line[NrLine].Note[N].Text); + for NoteIndex := 0 to Lines[0].Line[NrLine].HighNote do + begin + Italic := Lines[0].Line[NrLine].Note[NoteIndex].NoteType = ntFreestyle; + AddWord(Lines[0].Line[NrLine].Note[NoteIndex].Text); end; Selected := -1; end; @@ -220,32 +226,33 @@ end; procedure TEditorLyrics.Refresh; var - W: integer; - TotWidth: real; + WordIndex: integer; + TotalWidth: real; begin - if AlignI = 1 then begin - TotWidth := 0; - for W := 0 to High(Word) do - TotWidth := TotWidth + Word[W].Width; - - Word[0].X := XR - TotWidth / 2; - for W := 1 to High(Word) do - Word[W].X := Word[W - 1].X + Word[W - 1].Width; + if AlignI = center then + begin + TotalWidth := 0; + for WordIndex := 0 to High(Word) do + TotalWidth := TotalWidth + Word[WordIndex].Width; + + Word[0].X := XR - TotalWidth / 2; + for WordIndex := 1 to High(Word) do + Word[WordIndex].X := Word[WordIndex - 1].X + Word[WordIndex - 1].Width; end; end; procedure TEditorLyrics.Draw; var - W: integer; + WordIndex: integer; begin - for W := 0 to High(Word) do + for WordIndex := 0 to High(Word) do begin - SetFontStyle(Word[W].FontStyle); - SetFontPos(Word[W].X+ 10*ScreenX, Word[W].Y); - SetFontSize(Word[W].Size); - SetFontItalic(Word[W].Italic); - glColor3f(Word[W].ColR, Word[W].ColG, Word[W].ColB); - glPrint(Word[W].Text); + SetFontStyle(Word[WordIndex].FontStyle); + SetFontPos(Word[WordIndex].X + 10*ScreenX, Word[WordIndex].Y); + SetFontSize(Word[WordIndex].Size); + SetFontItalic(Word[WordIndex].Italic); + glColor3f(Word[WordIndex].ColR, Word[WordIndex].ColG, Word[WordIndex].ColB); + glPrint(Word[WordIndex].Text); end; end; diff --git a/unicode/src/base/UFiles.pas b/unicode/src/base/UFiles.pas index 463801c7..ee6f660a 100644 --- a/unicode/src/base/UFiles.pas +++ b/unicode/src/base/UFiles.pas @@ -58,8 +58,8 @@ implementation uses TextGL, UIni, - UPlatform, - UMain; + UNote, + UPlatform; //-------------------- // Resets the temporary Sentence Arrays for each Player and some other Variables @@ -73,7 +73,6 @@ begin SetLength(Lines[Count].Line, 1); SetLength(Lines[Count].Line[0].Note, 0); Lines[Count].Line[0].Lyric := ''; - Lines[Count].Line[0].LyricWidth := 0; Player[Count].Score := 0; Player[Count].LengthNote := 0; Player[Count].HighNote := -1; diff --git a/unicode/src/base/UGraphic.pas b/unicode/src/base/UGraphic.pas index b525c170..17175d02 100644 --- a/unicode/src/base/UGraphic.pas +++ b/unicode/src/base/UGraphic.pas @@ -280,11 +280,12 @@ function LoadingThreadFunction: integer; implementation uses + Classes, UMain, UIni, UDisplay, UCommandLine, - Classes; + UPath; procedure LoadFontTextures; begin @@ -294,17 +295,19 @@ end; procedure LoadTextures; - var - P: integer; - R, G, B: real; - Col: integer; + P: integer; + R, G, B: real; + Col: integer; begin Log.LogStatus('Loading Textures', 'LoadTextures'); - - Tex_Left[0] := Texture.LoadTexture(Skin.GetTextureFileName('GrayLeft'), TEXTURE_TYPE_TRANSPARENT, 0); //brauch man die noch? - Tex_Mid[0] := Texture.LoadTexture(Skin.GetTextureFileName('GrayMid'), TEXTURE_TYPE_PLAIN, 0); //brauch man die noch? - Tex_Right[0] := Texture.LoadTexture(Skin.GetTextureFileName('GrayRight'), TEXTURE_TYPE_TRANSPARENT, 0); //brauch man die noch? + + // FIXME: do we need this? (REMOVE otherwise) + Tex_Left[0] := Texture.LoadTexture(Skin.GetTextureFileName('GrayLeft'), TEXTURE_TYPE_TRANSPARENT, 0); + // FIXME: do we need this? (REMOVE otherwise) + Tex_Mid[0] := Texture.LoadTexture(Skin.GetTextureFileName('GrayMid'), TEXTURE_TYPE_PLAIN, 0); + // FIXME: do we need this? (REMOVE otherwise) + Tex_Right[0] := Texture.LoadTexture(Skin.GetTextureFileName('GrayRight'), TEXTURE_TYPE_TRANSPARENT, 0); Log.LogStatus('Loading Textures - A', 'LoadTextures'); diff --git a/unicode/src/base/UGraphicClasses.pas b/unicode/src/base/UGraphicClasses.pas index 3fbe262f..cdaa238e 100644 --- a/unicode/src/base/UGraphicClasses.pas +++ b/unicode/src/base/UGraphicClasses.pas @@ -124,16 +124,16 @@ var implementation uses - sysutils, + SysUtils, + Math, gl, + UCommon, + UDrawTexture, + UGraphic, UIni, - UMain, - UThemes, + UNote, USkins, - UGraphic, - UDrawTexture, - UCommon, - math; + UThemes; //TParticle constructor TParticle.Create(cX, cY : real; diff --git a/unicode/src/base/UHooks.pas b/unicode/src/base/UHooks.pas index ab830090..acf2bba7 100644 --- a/unicode/src/base/UHooks.pas +++ b/unicode/src/base/UHooks.pas @@ -46,23 +46,23 @@ type //Record that saves info from Subscriber PSubscriberInfo = ^TSubscriberInfo; TSubscriberInfo = record - Self: THandle; //ID of this Subscription (First word: ID of Subscription; 2nd word: ID of Hook) - Next: PSubscriberInfo; //Pointer to next Item in HookChain + Self: THandle; // ID of this Subscription (First word: ID of Subscription; 2nd word: ID of Hook) + Next: PSubscriberInfo; // Pointer to next Item in HookChain Owner: integer; //For Error Handling and Plugin Unloading. - //Here is s/t tricky - //To avoid writing of Wrapping Functions to Hook an Event with a Class - //We save a Normal Proc or a Method of a Class + // Here is s/t tricky + // To avoid writing of Wrapping Functions to Hook an Event with a Class + // We save a Normal Proc or a Method of a Class case isClass: boolean of - False: (Proc: TUS_Hook); //Proc that will be called on Event - True: (ProcOfClass: TUS_Hook_of_Object); + false: (Proc: TUS_Hook); //Proc that will be called on Event + true: (ProcOfClass: TUS_Hook_of_Object); end; TEventInfo = record - Name: string[60]; //Name of Event - FirstSubscriber: PSubscriberInfo; //First subscriber in chain - LastSubscriber: PSubscriberInfo; //Last " (for easier subscriber adding + Name: string[60]; // Name of Event + FirstSubscriber: PSubscriberInfo; // First subscriber in chain + LastSubscriber: PSubscriberInfo; // Last " (for easier subscriber adding) end; THookManager = class @@ -101,7 +101,8 @@ uses // Create - Creates Class and Set Standard Values //------------ constructor THookManager.Create(const SpacetoAllocate: word); -var I: integer; +var + I: integer; begin inherited Create(); @@ -121,7 +122,8 @@ end; // AddEvent - Adds an Event and return the Events Handle or 0 on Failure //------------ function THookManager.AddEvent (const EventName: Pchar): THandle; -var I: integer; +var + I: integer; begin Result := 0; @@ -177,7 +179,6 @@ begin hEvent := hEvent - 1; //Arrayindex is Handle - 1 Result := -1; - if (Length(Events) > hEvent) and (Events[hEvent].Name[1] <> chr(0)) then begin //Event exists //Free the Space for all Subscribers @@ -212,8 +213,8 @@ end; function THookManager.AddSubscriber (const EventName: Pchar; const Proc: TUS_Hook; const ProcOfClass: TUS_Hook_of_Object): THandle; var EventHandle: THandle; - EventIndex: Cardinal; - Cur: PSubscriberInfo; + EventIndex: integer; + Cur: PSubscriberInfo; begin Result := 0; @@ -224,7 +225,7 @@ begin if (EventHandle <> 0) then begin EventIndex := EventHandle - 1; - + //Get Memory GetMem(Cur, SizeOf(TSubscriberInfo)); @@ -236,12 +237,12 @@ begin if (@Proc = nil) then begin //Use the ProcofClass Method - Cur.isClass := True; + Cur.isClass := true; Cur.ProcOfClass := ProcofClass; end else //Use the normal Proc begin - Cur.isClass := False; + Cur.isClass := false; Cur.Proc := Proc; end; @@ -306,8 +307,8 @@ end; //------------ function THookManager.DelSubscriber (const hSubscriber: THandle): integer; var - EventIndex: Cardinal; - Cur, Last: PSubscriberInfo; + EventIndex: integer; + Cur, Last: PSubscriberInfo; begin Result := -1; EventIndex := ((hSubscriber and (High(THandle) xor High(word))) SHR 16) - 1; @@ -344,16 +345,15 @@ begin end; end; - //------------ // CallEventChain - Calls the Chain of a specified EventHandle // Returns: -1: Handle doesn't Exist, 0 Chain is called until the End //------------ function THookManager.CallEventChain (const hEvent: THandle; const wParam: TwParam; lParam: TlParam): integer; var - EventIndex: Cardinal; - Cur: PSubscriberInfo; - CurExecutedBackup: integer; //backup of Core.CurExecuted Attribute + EventIndex: integer; + Cur: PSubscriberInfo; + CurExecutedBackup: integer; // backup of Core.CurExecuted Attribute begin Result := -1; EventIndex := hEvent - 1; @@ -393,7 +393,7 @@ end; //------------ function THookManager.EventExists (const EventName: Pchar): integer; var - I: integer; + I: integer; Name: string[60]; begin Result := 0; @@ -418,7 +418,7 @@ end; //------------ procedure THookManager.DelbyOwner(const Owner: integer); var - I: integer; + I: integer; Cur, Last: PSubscriberInfo; begin //Search for Owner in all Hooks Chains @@ -426,7 +426,7 @@ begin begin if (Events[I].Name[1] <> chr(0)) then begin - + Last := nil; Cur := Events[I].FirstSubscriber; //Went Through Chain @@ -451,7 +451,6 @@ begin end; end; - function HookTest(wParam: TwParam; lParam: TlParam): integer; stdcall; begin Result := 0; //Don't break the chain diff --git a/unicode/src/base/UImage.pas b/unicode/src/base/UImage.pas index 18b0035c..8dc38495 100644 --- a/unicode/src/base/UImage.pas +++ b/unicode/src/base/UImage.pas @@ -151,10 +151,9 @@ function LoadImage(const Filename: string): PSDL_Surface; *******************************************************) function PixelFormatEquals(fmt1, fmt2: PSDL_PixelFormat): boolean; -procedure ScaleImage(var ImgSurface: PSDL_Surface; Width, Height: Cardinal); -procedure FitImage(var ImgSurface: PSDL_Surface; Width, Height: Cardinal); -procedure ColorizeImage(ImgSurface: PSDL_Surface; NewColor: Cardinal); - +procedure ScaleImage(var ImgSurface: PSDL_Surface; Width, Height: cardinal); +procedure FitImage(var ImgSurface: PSDL_Surface; Width, Height: cardinal); +procedure ColorizeImage(ImgSurface: PSDL_Surface; NewColor: cardinal); implementation @@ -185,7 +184,6 @@ uses UCommon, ULog; - function IsRGBSurface(pixelFmt: PSDL_PixelFormat): boolean; begin Result := (pixelFmt.BitsPerPixel = 24) and @@ -266,7 +264,6 @@ begin end; end; - (******************************************************* * Image saving *******************************************************) @@ -759,12 +756,10 @@ end; {$ENDIF} - (******************************************************* * Image loading *******************************************************) - (* * Loads an image from the given file *) @@ -793,12 +788,10 @@ begin end; end; - (******************************************************* * Image manipulation *******************************************************) - function PixelFormatEquals(fmt1, fmt2: PSDL_PixelFormat): boolean; begin if (fmt1^.BitsPerPixel = fmt2^.BitsPerPixel) and @@ -814,7 +807,7 @@ begin Result := false; end; -procedure ScaleImage(var ImgSurface: PSDL_Surface; Width, Height: Cardinal); +procedure ScaleImage(var ImgSurface: PSDL_Surface; Width, Height: cardinal); var TempSurface: PSDL_Surface; begin @@ -825,10 +818,10 @@ begin SDL_FreeSurface(TempSurface); end; -procedure FitImage(var ImgSurface: PSDL_Surface; Width, Height: Cardinal); +procedure FitImage(var ImgSurface: PSDL_Surface; Width, Height: cardinal); var TempSurface: PSDL_Surface; - ImgFmt: PSDL_PixelFormat; + ImgFmt: PSDL_PixelFormat; begin TempSurface := ImgSurface; @@ -849,12 +842,12 @@ end; (* // Old slow floating point version of ColorizeTexture. // For an easier understanding of the faster fixed point version below. -procedure ColorizeTexture(TexSurface: PSDL_Surface; Col: Cardinal); +procedure ColorizeTexture(TexSurface: PSDL_Surface; Col: cardinal); var - clr: array[0..2] of Double; // [0: R, 1: G, 2: B] - hsv: array[0..2] of Double; // [0: H(ue), 1: S(aturation), 2: V(alue)] - delta, f, p, q, t: Double; - max: Double; + clr: array[0..2] of double; // [0: R, 1: G, 2: B] + hsv: array[0..2] of double; // [0: H(ue), 1: S(aturation), 2: V(alue)] + delta, f, p, q, t: double; + max: double; begin clr[0] := PixelColors[0]/255; clr[1] := PixelColors[1]/255; @@ -892,90 +885,175 @@ begin end; *) -procedure ColorizeImage(ImgSurface: PSDL_Surface; NewColor: Cardinal); +procedure ColorizeImage(ImgSurface: PSDL_Surface; NewColor: cardinal); - //returns hue within range [0.0-6.0) - function col2hue(Color:Cardinal): double; + // First, the rgb colors are converted to hsv, second hue is replaced by + // the NewColor, saturation and value remain unchanged, finally this + // hsv color is converted back to rgb space. + // For the conversion algorithms of colors from rgb to hsv space + // and back simply check the wikipedia. + // In order to speed up starting time of USDX the division of reals is + // replaced by division of longwords, shifted by 10 bits to keep + // digits. + + function ColorToHue(const Color: longword): longword; + // returns hue within the range [0.0-6.0] but shl 10, ie. times 1024 var - clr: array[0..2] of double; - hue, max, delta: double; + Red, Green, Blue: longword; + Min, Max, Delta: longword; + Hue: double; begin - clr[0] := ((Color and $ff0000) shr 16)/255; // R - clr[1] := ((Color and $ff00) shr 8)/255; // G - clr[2] := (Color and $ff) /255; // B - max := maxvalue(clr); - delta := max - minvalue(clr); + // extract the colors + // division by 255 is omitted, since it is implicitly done + // when deviding by delta + Red := ((Color and $ff0000) shr 16); // R + Green := ((Color and $ff00) shr 8); // G + Blue := (Color and $ff) ; // B + + Min := Red; + if Green < Min then Min := Green; + if Blue < Min then Min := Blue; + + Max := Red; + if Green > Max then Max := Green; + if Blue > Max then Max := Blue; + // calc hue - if (delta = 0.0) then hue := 0 - else if (clr[0] = max) then hue := (clr[1]-clr[2])/delta - else if (clr[1] = max) then hue := 2.0+(clr[2]-clr[0])/delta - else if (clr[2] = max) then hue := 4.0+(clr[0]-clr[1])/delta; - if (hue < 0.0) then - hue := hue + 6.0; - Result := hue; + Delta := Max - Min; + if (Delta = 0) then + Result := 0 + else + begin + // The division by Delta is done separately afterwards. + // Necessary because Delphi did not do the type conversion from + // longword to double as expected. + if (Max = Red ) then Hue := Green - Blue + else if (Max = Green) then Hue := 2.0*Delta + Blue - Red + else if (Max = Blue ) then Hue := 4.0*Delta + Red - Green; + Hue := Hue / Delta; + if (Hue < 0.0) then + Hue := Hue + 6.0; + Result := trunc(Hue*1024); // '*1024' is shl 10 + end; end; var - DestinationHue: Double; - PixelIndex: Cardinal; + PixelIndex: longword; Pixel: PByte; PixelColors: PByteArray; - clr: array[0..2] of UInt32; // [0: R, 1: G, 2: B] - hsv: array[0..2] of UInt32; // [0: H(ue), 1: S(aturation), 2: V(alue)] - dhue: UInt32; - h_int: Cardinal; - delta, f, p, q, t: Longint; - max: Uint32; + Red, Green, Blue: longword; + Hue, Sat: longword; + Min, Max, Delta: longword; + HueInteger: longword; + f, p, q, t: longword; begin - DestinationHue := col2hue(NewColor); - - dhue := Trunc(DestinationHue*1024); Pixel := ImgSurface^.Pixels; + // check of the size of a pixel in bytes. + // It should be always 4, but this + // additional safeguard will show, + // whether something went wrong up to here. + + if ImgSurface^.format.BytesPerPixel <> 4 then + Log.LogError ('ColorizeImage: The pixel size should be 4, but it is ' + + IntToStr(ImgSurface^.format.BytesPerPixel)); + + Hue := ColorToHue(NewColor); // Hue is shl 10 + f := Hue and $3ff; // f is the dezimal part of hue + HueInteger := Hue shr 10; + for PixelIndex := 0 to (ImgSurface^.W * ImgSurface^.H)-1 do begin PixelColors := PByteArray(Pixel); // inlined colorize per pixel // uses fixed point math + // shl 10 is used for divisions + // get color values - clr[0] := PixelColors[0] shl 10; - clr[1] := PixelColors[1] shl 10; - clr[2] := PixelColors[2] shl 10; + + {$IFDEF FPC_BIG_ENDIAN} + Red := PixelColors[3]; + Green := PixelColors[2]; + Blue := PixelColors[1]; + // PixelColors[0] is alpha and remains untouched + {$ELSE} + Red := PixelColors[0]; + Green := PixelColors[1]; + Blue := PixelColors[2]; + // PixelColors[3] is alpha and remains untouched + {$ENDIF} + //calculate luminance and saturation from rgb - max := clr[0]; - if clr[1] > max then max := clr[1]; - if clr[2] > max then max := clr[2]; - delta := clr[0]; - if clr[1] < delta then delta := clr[1]; - if clr[2] < delta then delta := clr[2]; - delta := max-delta; - hsv[0] := dhue; // shl 8 - hsv[2] := max; // shl 8 - if (max = 0) then - hsv[1] := 0 + Max := Red; + if Green > Max then Max := Green; + if Blue > Max then Max := Blue ; + + if (Max = 0) then // the color is black + begin + {$IFDEF FPC_BIG_ENDIAN} + PixelColors[3] := 0; + PixelColors[2] := 0; + PixelColors[1] := 0; + {$ELSE} + PixelColors[0] := 0; + PixelColors[1] := 0; + PixelColors[2] := 0; + {$ENDIF} + end else - hsv[1] := (delta shl 10) div max; // shl 8 - h_int := hsv[0] and $fffffC00; - f := hsv[0]-h_int; //shl 10 - p := (hsv[2]*(1024-hsv[1])) shr 10; - q := (hsv[2]*(1024-(hsv[1]*f) shr 10)) shr 10; - t := (hsv[2]*(1024-(hsv[1]*(1024-f)) shr 10)) shr 10; - h_int := h_int shr 10; - case h_int of - 0: begin clr[0] := hsv[2]; clr[1] := t; clr[2] := p; end; // (v,t,p) - 1: begin clr[0] := q; clr[1] := hsv[2]; clr[2] := p; end; // (q,v,p) - 2: begin clr[0] := p; clr[1] := hsv[2]; clr[2] := t; end; // (p,v,t) - 3: begin clr[0] := p; clr[1] := q; clr[2] := hsv[2]; end; // (p,q,v) - 4: begin clr[0] := t; clr[1] := p; clr[2] := hsv[2]; end; // (t,p,v) - 5: begin clr[0] := hsv[2]; clr[1] := p; clr[2] := q; end; // (v,p,q) - end; + begin + Min := Red; + if Green < Min then Min := Green; + if Blue < Min then Min := Blue ; + + if (Min = 255) then // the color is white + begin + {$IFDEF FPC_BIG_ENDIAN} + PixelColors[3] := 255; + PixelColors[2] := 255; + PixelColors[1] := 255; + {$ELSE} + PixelColors[0] := 255; + PixelColors[1] := 255; + PixelColors[2] := 255; + {$ENDIF} + end + else // all colors except black and white + begin + Delta := Max - Min; + Sat := (Delta shl 10) div Max; // shl 10 + + // shr 10 corrects that sat and f are shl 10 + // the resulting p, q and t are unshifted + + p := (Max*(1024-Sat)) shr 10; + q := (Max*(1024-(Sat*f) shr 10)) shr 10; + t := (Max*(1024-(Sat*(1024-f)) shr 10)) shr 10; + + case HueInteger of + 0: begin Red := Max; Green := t; Blue := p; end; // (v,t,p) + 1: begin Red := q; Green := Max; Blue := p; end; // (q,v,p) + 2: begin Red := p; Green := Max; Blue := t; end; // (p,v,t) + 3: begin Red := p; Green := q; Blue := Max; end; // (p,q,v) + 4: begin Red := t; Green := p; Blue := Max; end; // (t,p,v) + 5: begin Red := Max; Green := p; Blue := q; end; // (v,p,q) + end; + + {$IFDEF FPC_BIG_ENDIAN} + PixelColors[3] := Red; + PixelColors[2] := Green; + PixelColors[1] := Blue + {$ELSE} + PixelColors[0] := Red; + PixelColors[1] := Green; + PixelColors[2] := Blue; + {$ENDIF} - PixelColors[0] := clr[0] shr 10; - PixelColors[1] := clr[1] shr 10; - PixelColors[2] := clr[2] shr 10; + end; + end; Inc(Pixel, ImgSurface^.format.BytesPerPixel); end; diff --git a/unicode/src/base/UIni.pas b/unicode/src/base/UIni.pas index e90ae31c..241b34e8 100644 --- a/unicode/src/base/UIni.pas +++ b/unicode/src/base/UIni.pas @@ -74,7 +74,7 @@ type function RemoveFileExt(FullName: string): string; function ExtractKeyIndex(const Key, Prefix, Suffix: string): integer; function GetMaxKeyIndex(Keys: TStringList; const Prefix, Suffix: string): integer; - function GetArrayIndex(const SearchArray: array of string; Value: string; CaseInsensitiv: Boolean = False): integer; + function GetArrayIndex(const SearchArray: array of string; Value: string; CaseInsensitiv: boolean = false): integer; function ReadArrayIndex(const SearchArray: array of string; IniFile: TCustomIniFile; IniSection: string; IniProperty: string; Default: integer): integer; @@ -99,7 +99,7 @@ type Difficulty: integer; Language: integer; Tabs: integer; - Tabs_at_startup:integer; //Tabs at Startup fix + TabsAtStartup: integer; //Tabs at Startup fix Sorting: integer; Debug: integer; @@ -107,7 +107,7 @@ type Screens: integer; Resolution: integer; Depth: integer; - VisualizerOption:integer; + VisualizerOption: integer; FullScreen: integer; TextureSize: integer; SingWindow: integer; @@ -122,8 +122,8 @@ type BeatClick: integer; SavePlayback: integer; ThresholdIndex: integer; - AudioOutputBufferSizeIndex:integer; - VoicePassthrough:integer; + AudioOutputBufferSizeIndex: integer; + VoicePassthrough: integer; //Song Preview PreviewVolume: integer; @@ -139,8 +139,8 @@ type Theme: integer; SkinNo: integer; Color: integer; - BackgroundMusicOption:integer; - + BackgroundMusicOption: integer; + // Record InputDeviceConfig: array of TInputDeviceConfig; @@ -166,22 +166,20 @@ type end; var - Ini: TIni; - IResolution: array of string; - ILanguage: array of string; - ITheme: array of string; - ISkin: array of string; - - + Ini: TIni; + IResolution: array of string; + ILanguage: array of string; + ITheme: array of string; + ISkin: array of string; const - IPlayers: array[0..4] of string = ('1', '2', '3', '4', '6'); - IPlayersVals: array[0..4] of integer = ( 1 , 2 , 3 , 4 , 6 ); + IPlayers: array[0..4] of string = ('1', '2', '3', '4', '6'); + IPlayersVals: array[0..4] of integer = ( 1 , 2 , 3 , 4 , 6 ); - IDifficulty: array[0..2] of string = ('Easy', 'Medium', 'Hard'); - ITabs: array[0..1] of string = ('Off', 'On'); + IDifficulty: array[0..2] of string = ('Easy', 'Medium', 'Hard'); + ITabs: array[0..1] of string = ('Off', 'On'); - ISorting: array[0..7] of string = ('Edition', 'Genre', 'Language', 'Folder', 'Title', 'Artist', 'Title2', 'Artist2'); + ISorting: array[0..7] of string = ('Edition', 'Genre', 'Language', 'Folder', 'Title', 'Artist', 'Title2', 'Artist2'); sEdition = 0; sGenre = 1; sLanguage = 2; @@ -191,51 +189,49 @@ const sTitle2 = 6; sArtist2 = 7; - IDebug: array[0..1] of string = ('Off', 'On'); + IDebug: array[0..1] of string = ('Off', 'On'); - IScreens: array[0..1] of string = ('1', '2'); - IFullScreen: array[0..1] of string = ('Off', 'On'); - IDepth: array[0..1] of string = ('16 bit', '32 bit'); - IVisualizer: array[0..2] of string = ('Off', 'WhenNoVideo','On'); + IScreens: array[0..1] of string = ('1', '2'); + IFullScreen: array[0..1] of string = ('Off', 'On'); + IDepth: array[0..1] of string = ('16 bit', '32 bit'); + IVisualizer: array[0..2] of string = ('Off', 'WhenNoVideo','On'); - IBackgroundMusic: array[0..1] of string = ('Off', 'On'); + IBackgroundMusic: array[0..1] of string = ('Off', 'On'); + ITextureSize: array[0..2] of string = ('128', '256', '512'); + ITextureSizeVals: array[0..2] of integer = ( 128, 256, 512); - ITextureSize: array[0..2] of string = ('128', '256', '512'); - ITextureSizeVals: array[0..2] of integer = ( 128, 256, 512); - - ISingWindow: array[0..1] of string = ('Small', 'Big'); + ISingWindow: array[0..1] of string = ('Small', 'Big'); //SingBar Mod - IOscilloscope: array[0..2] of string = ('Off', 'Osci', 'Bar'); -//IOscilloscope: array[0..1] of string = ('Off', 'On'); + IOscilloscope: array[0..2] of string = ('Off', 'Osci', 'Bar'); +//IOscilloscope: array[0..1] of string = ('Off', 'On'); - ISpectrum: array[0..1] of string = ('Off', 'On'); - ISpectrograph: array[0..1] of string = ('Off', 'On'); - IMovieSize: array[0..2] of string = ('Half', 'Full [Vid]', 'Full [BG+Vid]'); + ISpectrum: array[0..1] of string = ('Off', 'On'); + ISpectrograph: array[0..1] of string = ('Off', 'On'); + IMovieSize: array[0..2] of string = ('Half', 'Full [Vid]', 'Full [BG+Vid]'); - IClickAssist: array[0..1] of string = ('Off', 'On'); - IBeatClick: array[0..1] of string = ('Off', 'On'); - ISavePlayback: array[0..1] of string = ('Off', 'On'); + IClickAssist: array[0..1] of string = ('Off', 'On'); + IBeatClick: array[0..1] of string = ('Off', 'On'); + ISavePlayback: array[0..1] of string = ('Off', 'On'); - IThreshold: array[0..3] of string = ('5%', '10%', '15%', '20%'); - IThresholdVals: array[0..3] of single = (0.05, 0.10, 0.15, 0.20); + IThreshold: array[0..3] of string = ('5%', '10%', '15%', '20%'); + IThresholdVals: array[0..3] of single = (0.05, 0.10, 0.15, 0.20); - IVoicePassthrough: array[0..1] of string = ('Off', 'On'); + IVoicePassthrough: array[0..1] of string = ('Off', 'On'); IAudioOutputBufferSize: array[0..9] of string = ('Auto', '256', '512', '1024', '2048', '4096', '8192', '16384', '32768', '65536'); IAudioOutputBufferSizeVals: array[0..9] of integer = ( 0, 256, 512 , 1024 , 2048 , 4096 , 8192 , 16384 , 32768 , 65536 ); - IAudioInputBufferSize: array[0..9] of string = ('Auto', '256', '512', '1024', '2048', '4096', '8192', '16384', '32768', '65536'); - IAudioInputBufferSizeVals: array[0..9] of integer = ( 0, 256, 512 , 1024 , 2048 , 4096 , 8192 , 16384 , 32768 , 65536 ); + IAudioInputBufferSize: array[0..9] of string = ('Auto', '256', '512', '1024', '2048', '4096', '8192', '16384', '32768', '65536'); + IAudioInputBufferSizeVals: array[0..9] of integer = ( 0, 256, 512 , 1024 , 2048 , 4096 , 8192 , 16384 , 32768 , 65536 ); //Song Preview - IPreviewVolume: array[0..10] of string = ('Off', '10%', '20%', '30%', '40%', '50%', '60%', '70%', '80%', '90%', '100%'); - IPreviewVolumeVals: array[0..10] of single = ( 0, 0.10, 0.20, 0.30, 0.40, 0.50, 0.60, 0.70, 0.80, 0.90, 1.00 ); - - IPreviewFading: array[0..5] of string = ('Off', '1 Sec', '2 Secs', '3 Secs', '4 Secs', '5 Secs'); - IPreviewFadingVals: array[0..5] of integer = ( 0, 1, 2, 3, 4, 5 ); + IPreviewVolume: array[0..10] of string = ('Off', '10%', '20%', '30%', '40%', '50%', '60%', '70%', '80%', '90%', '100%'); + IPreviewVolumeVals: array[0..10] of single = ( 0, 0.10, 0.20, 0.30, 0.40, 0.50, 0.60, 0.70, 0.80, 0.90, 1.00 ); + IPreviewFading: array[0..5] of string = ('Off', '1 Sec', '2 Secs', '3 Secs', '4 Secs', '5 Secs'); + IPreviewFadingVals: array[0..5] of integer = ( 0, 1, 2, 3, 4, 5 ); ILyricsFont: array[0..2] of string = ('Plain', 'OLine1', 'OLine2'); ILyricsEffect: array[0..4] of string = ('Simple', 'Zoom', 'Slide', 'Ball', 'Shift'); @@ -247,7 +243,7 @@ const // Advanced ILoadAnimation: array[0..1] of string = ('Off', 'On'); IEffectSing: array[0..1] of string = ('Off', 'On'); - IScreenFade: array[0..1] of string =('Off', 'On'); + IScreenFade: array[0..1] of string = ('Off', 'On'); IAskbeforeDel: array[0..1] of string = ('Off', 'On'); IOnSongClick: array[0..2] of string = ('Sing', 'Select Players', 'Open Menu'); ILineBonus: array[0..2] of string = ('Off', 'At Score', 'At Notes'); @@ -270,6 +266,7 @@ uses USkins, URecord, UCommandLine, + UPath, UUnicodeUtils; (** @@ -288,17 +285,22 @@ function TIni.ExtractKeyIndex(const Key, Prefix, Suffix: string): integer; var Value: string; Start: integer; + PrefixPos, SuffixPos: integer; begin Result := -1; - if Pos(Prefix, Key) > -1 then - begin - Start := Pos(Prefix, Key) + Length(Prefix); + PrefixPos := Pos(Prefix, Key); + if (PrefixPos <= 0) then + Exit; + SuffixPos := Pos(Suffix, Key); + if (SuffixPos <= 0) then + Exit; - // copy all between prefix and suffix - Value := Copy(Key, Start, Pos(Suffix, Key)-1 - Start); - Result := StrToIntDef(Value, -1); - end; + Start := PrefixPos + Length(Prefix); + + // copy all between prefix and suffix + Value := Copy(Key, Start, SuffixPos - Start); + Result := StrToIntDef(Value, -1); end; (** @@ -308,7 +310,7 @@ end; *) function TIni.GetMaxKeyIndex(Keys: TStringList; const Prefix, Suffix: string): integer; var - i: integer; + i: integer; KeyIndex: integer; begin Result := -1; @@ -326,7 +328,7 @@ end; * or -1 if Value is not in SearchArray. *) function TIni.GetArrayIndex(const SearchArray: array of string; Value: string; - CaseInsensitiv: Boolean = False): integer; + CaseInsensitiv: boolean = false): integer; var i: integer; begin @@ -362,15 +364,14 @@ begin end; end; - procedure TIni.LoadInputDeviceCfg(IniFile: TMemIniFile); var - DeviceCfg: PInputDeviceConfig; - DeviceIndex: integer; + DeviceCfg: PInputDeviceConfig; + DeviceIndex: integer; ChannelCount: integer; ChannelIndex: integer; - RecordKeys: TStringList; - i: integer; + RecordKeys: TStringList; + i: integer; begin RecordKeys := TStringList.Create(); @@ -419,15 +420,15 @@ begin RecordKeys.Free(); // MicBoost - //MicBoost := GetArrayIndex(IMicBoost, IniFile.ReadString('Record', 'MicBoost', 'Off')); + MicBoost := GetArrayIndex(IMicBoost, IniFile.ReadString('Record', 'MicBoost', 'Off')); // Threshold - // ThresholdIndex := GetArrayIndex(IThreshold, IniFile.ReadString('Record', 'Threshold', IThreshold[1])); + ThresholdIndex := GetArrayIndex(IThreshold, IniFile.ReadString('Record', 'Threshold', IThreshold[1])); end; procedure TIni.SaveInputDeviceCfg(IniFile: TIniFile); var - DeviceIndex: integer; - ChannelIndex: integer; + DeviceIndex: integer; + ChannelIndex: integer; begin for DeviceIndex := 0 to High(InputDeviceConfig) do begin @@ -436,7 +437,7 @@ begin InputDeviceConfig[DeviceIndex].Name); IniFile.WriteInteger('Record', Format('Input[%d]', [DeviceIndex+1]), InputDeviceConfig[DeviceIndex].Input); - + // Channel-to-Player Mapping for ChannelIndex := 0 to High(InputDeviceConfig[DeviceIndex].ChannelToPlayerMap) do begin @@ -447,15 +448,15 @@ begin end; // MicBoost - //IniFile.WriteString('Record', 'MicBoost', IMicBoost[MicBoost]); + IniFile.WriteString('Record', 'MicBoost', IMicBoost[MicBoost]); // Threshold - //IniFile.WriteString('Record', 'Threshold', IThreshold[ThresholdIndex]); + IniFile.WriteString('Record', 'Threshold', IThreshold[ThresholdIndex]); end; procedure TIni.LoadPaths(IniFile: TCustomIniFile); var PathStrings: TStringList; - I: integer; + I: integer; begin PathStrings := TStringList.Create; IniFile.ReadSection('Directories', PathStrings); @@ -513,7 +514,7 @@ begin Theme := GetArrayIndex(ITheme, IniFile.ReadString('Themes', 'Theme', 'DELUXE'), true); if (Theme = -1) then - Theme := 0; + Theme := 0; // Skin Skin.onThemeChange; @@ -535,25 +536,25 @@ procedure TIni.LoadScreenModes(IniFile: TCustomIniFile); var Modes: PPSDL_Rect; - I: integer; + I: integer; begin // Screens Screens := GetArrayIndex(IScreens, IniFile.ReadString('Graphics', 'Screens', IScreens[0])); - + // FullScreen FullScreen := GetArrayIndex(IFullScreen, IniFile.ReadString('Graphics', 'FullScreen', 'On')); // Resolution SetLength(IResolution, 0); - + // Check if there are any modes available // TODO: we should seperate windowed and fullscreen modes. Otherwise it is not // possible to select a reasonable fullscreen mode when in windowed mode if IFullScreen[FullScreen] = 'On' then Modes := SDL_ListModes(nil, SDL_OPENGL or SDL_FULLSCREEN) - else + else Modes := SDL_ListModes(nil, SDL_OPENGL or SDL_RESIZABLE) ; - + if (Modes = nil) then begin Log.LogStatus( 'No resolutions Found' , 'Video'); @@ -572,7 +573,7 @@ begin IResolution[7] := '1440x900'; IResolution[8] := '1600x1200'; IResolution[9] := '1680x1050'; - + Resolution := GetArrayIndex(IResolution, IniFile.ReadString('Graphics', 'Resolution', '800x600')); if Resolution = -1 then begin @@ -628,7 +629,7 @@ end; procedure TIni.Load(); var IniFile: TMemIniFile; - I: integer; + I: integer; begin GamePath := Platform.GetGameUserPath; @@ -655,24 +656,24 @@ begin NameTeam[I] := IniFile.ReadString('NameTeam', 'T'+IntToStr(I+1), 'Team'+IntToStr(I+1)); for I := 0 to 11 do NameTemplate[I] := IniFile.ReadString('NameTemplate', 'Name'+IntToStr(I+1), 'Template'+IntToStr(I+1)); - + // Players Players := GetArrayIndex(IPlayers, IniFile.ReadString('Game', 'Players', IPlayers[0])); - + // Difficulty Difficulty := GetArrayIndex(IDifficulty, IniFile.ReadString('Game', 'Difficulty', 'Easy')); - + // Language Language := GetArrayIndex(ILanguage, IniFile.ReadString('Game', 'Language', 'English')); //Language.ChangeLanguage(ILanguage[Language]); - + // Tabs Tabs := GetArrayIndex(ITabs, IniFile.ReadString('Game', 'Tabs', ITabs[0])); - Tabs_at_startup := Tabs; //Tabs at Startup fix - + TabsAtStartup := Tabs; //Tabs at Startup fix + // Song Sorting Sorting := GetArrayIndex(ISorting, IniFile.ReadString('Game', 'Sorting', ISorting[0])); - + // Debug Debug := GetArrayIndex(IDebug, IniFile.ReadString('Game', 'Debug', IDebug[0])); @@ -710,7 +711,7 @@ begin //Preview Volume PreviewVolume := GetArrayIndex(IPreviewVolume, IniFile.ReadString('Sound', 'PreviewVolume', IPreviewVolume[7])); - + //Preview Fading PreviewFading := GetArrayIndex(IPreviewFading, IniFile.ReadString('Sound', 'PreviewFading', IPreviewFading[1])); @@ -778,13 +779,13 @@ begin Joypad := GetArrayIndex(IJoypad, IniFile.ReadString('Controller', 'Joypad', IJoypad[0])); LoadPaths(IniFile); - + IniFile.Free; end; procedure TIni.Save; var - IniFile: TIniFile; + IniFile: TIniFile; begin if (FileExists(Filename) and FileIsReadOnly(Filename)) then begin @@ -859,7 +860,7 @@ begin // Song Preview IniFile.WriteString('Sound', 'PreviewVolume', IPreviewVolume[PreviewVolume]); - + // PreviewFading IniFile.WriteString('Sound', 'PreviewFading', IPreviewFading[PreviewFading]); diff --git a/unicode/src/base/ULanguage.pas b/unicode/src/base/ULanguage.pas index a89ded2d..f79f4165 100644 --- a/unicode/src/base/ULanguage.pas +++ b/unicode/src/base/ULanguage.pas @@ -78,7 +78,8 @@ uses IniFiles, Classes, SysUtils, - ULog; + ULog, + UPath; {** * LoadList, set default language, set standard implode glues diff --git a/unicode/src/base/ULog.pas b/unicode/src/base/ULog.pas index 582120bc..a872729a 100644 --- a/unicode/src/base/ULog.pas +++ b/unicode/src/base/ULog.pas @@ -132,7 +132,8 @@ uses UMain, UTime, UCommon, - UCommandLine; + UCommandLine, + UPath; (* * Write to console if in debug mode (Thread-safe). diff --git a/unicode/src/base/UMain.pas b/unicode/src/base/UMain.pas index ce25d16e..8d11b91d 100644 --- a/unicode/src/base/UMain.pas +++ b/unicode/src/base/UMain.pas @@ -35,109 +35,15 @@ interface uses SysUtils, - Classes, - SDL, - UMusic, - URecord, - UTime, - UDisplay, - UIni, - ULog, - ULyrics, - UScreenSing, - USong, - gl; - -type - PPLayerNote = ^TPlayerNote; - TPlayerNote = record - Start: integer; - Length: integer; - Detect: real; // accurate place, detected in the note - Tone: real; - Perfect: boolean; // true if the note matches the original one, lit the star - Hit: boolean; // true if the note Hits the Line - end; - - PPLayer = ^TPlayer; - TPlayer = record - Name: string; - - // Index in Teaminfo record - TeamID: Byte; - PlayerID: Byte; - - // Scores - Score: real; - ScoreLine: real; - ScoreGolden: real; - - ScoreInt: integer; - ScoreLineInt: integer; - ScoreGoldenInt: integer; - ScoreTotalInt: integer; - - // LineBonus - ScoreLast: Real;//Last Line Score - - // PerfectLineTwinkle (effect) - LastSentencePerfect: Boolean; - - HighNote: integer; // index of last note (= High(Note)?) - LengthNote: integer; // number of notes (= Length(Note)?). - Note: array of TPlayerNote; - end; - + SDL; var - // Absolute Paths - GamePath: string; - SoundPath: string; - SongPaths: TStringList; - LogPath: string; - ThemePath: string; - SkinsPath: string; - ScreenshotsPath: string; - CoverPaths: TStringList; - LanguagesPath: string; - PluginPath: string; - VisualsPath: string; - FontPath: string; - ResourcesPath: string; - PlayListPath: string; - - Done: Boolean; - // FIXME: ConversionFileName should not be global - ConversionFileName: string; - Restart: boolean; - - // player and music info - Player: array of TPlayer; - PlayersPlay: integer; - - CurrentSong : TSong; - -const - MAX_SONG_SCORE = 10000; // max. achievable points per song - MAX_SONG_LINE_BONUS = 1000; // max. achievable line bonus per song - - -function FindPath(out PathResult: string; const RequestedPath: string; NeedsWritePermission: boolean): boolean; -procedure InitializePaths; -procedure AddSongPath(const Path: string); + Done: boolean; + Restart: boolean; procedure Main; procedure MainLoop; procedure CheckEvents; -procedure Sing(Screen: TScreenSing); -procedure NewSentence(Screen: TScreenSing); -procedure NewBeatClick(Screen: TScreenSing); // executed when on then new beat for click -procedure NewBeatDetect(Screen: TScreenSing); // executed when on then new beat for detection -procedure NewNote(Screen: TScreenSing); // detect note -function GetMidBeat(Time: real): real; -function GetTimeFromBeat(Beat: integer): real; -procedure ClearScores(PlayerNum: integer); - type TMainThreadExecProc = procedure(Data: Pointer); @@ -155,48 +61,51 @@ const *} procedure MainThreadExec(Proc: TMainThreadExecProc; Data: Pointer); - implementation uses Math, - StrUtils, - USongs, - UJoystick, + gl, +{ + SDL_ttf, + UParty, + UCore, +} + UCatCovers, UCommandLine, - ULanguage, - //SDL_ttf, - USkins, + UCommon, + UConfig, UCovers, - UCatCovers, UDataBase, - UPlaylist, + UDisplay, UDLLManager, - UParty, - UConfig, - UCore, - UCommon, UGraphic, UGraphicClasses, - UPluginDefs, + UIni, + UJoystick, + ULanguage, + ULog, + UPath, + UPlaylist, + UMusic, UPlatform, - UThemes; - - - + USkins, + USongs, + UThemes, + UTime; procedure Main; var - WndTitle: string; + WindowTitle: string; begin {$IFNDEF Debug} try {$ENDIF} - WndTitle := USDXVersionStr; + WindowTitle := USDXVersionStr; Platform.Init; - if Platform.TerminateIfAlreadyRunning(WndTitle) then + if Platform.TerminateIfAlreadyRunning(WindowTitle) then Exit; // fix floating-point exceptions (FPE) @@ -210,11 +119,11 @@ begin DecimalSeparator := '.'; //------------------------------ - //StartUp - Create Classes and Load Files + // StartUp - create classes and load files //------------------------------ - // Initialize SDL - // Without SDL_INIT_TIMER SDL_GetTicks() might return strange values + // initialize SDL + // without SDL_INIT_TIMER SDL_GetTicks() might return strange values SDL_Init(SDL_INIT_VIDEO or SDL_INIT_TIMER); SDL_EnableUnicode(1); @@ -226,7 +135,7 @@ begin // Log + Benchmark Log := TLog.Create; - Log.Title := WndTitle; + Log.Title := WindowTitle; Log.FileOutputEnabled := not Params.NoLog; Log.BenchmarkStart(0); @@ -237,19 +146,19 @@ begin Log.LogStatus('Load Language', 'Initialization'); Language := TLanguage.Create; - // Add Const Values: + // add const values: Language.AddConst('US_VERSION', USDXVersionStr); Log.BenchmarkEnd(1); Log.LogBenchmark('Loading Language', 1); - { +{ // SDL_ttf (Not used yet, maybe in version 1.5) Log.BenchmarkStart(1); Log.LogStatus('Initialize SDL_ttf', 'Initialization'); TTF_Init(); Log.BenchmarkEnd(1); Log.LogBenchmark('Initializing SDL_ttf', 1); - } +} // Skin Log.BenchmarkStart(1); @@ -264,7 +173,7 @@ begin Ini := TIni.Create; Ini.Load; - //it's possible that this is the first run, create a .ini file if neccessary + // it is possible that this is the first run, create a .ini file if neccessary Log.LogStatus('Write Ini', 'Initialization'); Ini.Save; @@ -327,18 +236,19 @@ begin Log.BenchmarkEnd(1); Log.LogBenchmark('Loading PluginManager', 1); - {// Party Mode Manager +{ + // Party Mode Manager Log.BenchmarkStart(1); Log.LogStatus('PartySession Manager', 'Initialization'); PartySession := TPartySession.Create; //Load PartySession - Log.BenchmarkEnd(1); - Log.LogBenchmark('Loading PartySession Manager', 1); } + Log.LogBenchmark('Loading PartySession Manager', 1); +} // Graphics Log.BenchmarkStart(1); Log.LogStatus('Initialize 3D', 'Initialization'); - Initialize3D(WndTitle); + Initialize3D(WindowTitle); Log.BenchmarkEnd(1); Log.LogBenchmark('Initializing 3D', 1); @@ -370,7 +280,7 @@ begin Log.LogBenchmark('Loading Particle System', 1); // Joypad - if (Ini.Joypad = 1) OR (Params.Joypad) then + if (Ini.Joypad = 1) or (Params.Joypad) then begin Log.BenchmarkStart(1); Log.LogStatus('Initialize Joystick', 'Initialization'); @@ -383,19 +293,21 @@ begin Log.LogBenchmark('Loading Time', 0); Log.LogStatus('Creating Core', 'Initialization'); - {Core := TCore.Create( +{ + Core := TCore.Create( USDXShortVersionStr, MakeVersion(USDX_VERSION_MAJOR, USDX_VERSION_MINOR, USDX_VERSION_RELEASE, chr(0)) - ); } + ); +} Log.LogStatus('Running Core', 'Initialization'); //Core.Run; //------------------------------ - //Start- Mainloop + // Start Mainloop //------------------------------ Log.LogStatus('Main Loop', 'Initialization'); MainLoop; @@ -404,12 +316,12 @@ begin finally {$ENDIF} //------------------------------ - //Finish Application + // Finish Application //------------------------------ // TODO: // call an uninitialize routine for every initialize step - // or at least use the corresponding Free-Methods + // or at least use the corresponding Free methods FinalizeMedia(); @@ -428,7 +340,7 @@ end; procedure MainLoop; var - Delay: integer; + Delay: integer; const MAX_FPS = 100; begin @@ -445,7 +357,7 @@ begin CheckEvents; // display - done := not Display.Draw; + Done := not Display.Draw; SwapBuffers; // delay @@ -466,7 +378,7 @@ begin end; end; -End; +end; procedure CheckEvents; var @@ -474,7 +386,7 @@ var begin if Assigned(Display.NextScreen) then Exit; - + while (SDL_PollEvent(@Event) <> 0) do begin case Event.type_ of @@ -482,19 +394,19 @@ begin begin Display.Fade := 0; Display.NextScreenWithCheck := nil; - Display.CheckOK := True; + Display.CheckOK := true; end; SDL_MOUSEBUTTONDOWN: begin - { +{ with Event.button do begin - if State = SDL_BUTTON_LEFT Then + if State = SDL_BUTTON_LEFT then begin // end; end; - } +} end; SDL_VIDEORESIZE: begin @@ -503,7 +415,7 @@ begin // Note: do NOT call SDL_SetVideoMode on Windows and MacOSX here. // This would create a new OpenGL render-context and all texture data // would be invalidated. - // On Linux the mode MUST be resetted, otherwise graphics will be corrupted. + // On Linux the mode MUST be reset, otherwise graphics will be corrupted. {$IF Defined(Linux) or Defined(FreeBSD)} if boolean( Ini.FullScreen ) then SDL_SetVideoMode(ScreenW, ScreenH, (Ini.Depth+1) * 16, SDL_OPENGL or SDL_FULLSCREEN) @@ -525,7 +437,7 @@ begin // FIXME: SDL_SetVideoMode creates a new OpenGL RC so we have to // reload all texture data (-> whitescreen bug). - // Only Linux (and FreeBSD) is able to handle screen-switching this way. + // Only Linux and FreeBSD are able to handle screen-switching this way. {$IF Defined(Linux) or Defined(FreeBSD)} if boolean( Ini.FullScreen ) then begin @@ -547,16 +459,16 @@ begin // if there is a visible popup then let it handle input instead of underlying screen // shoud be done in a way to be sure the topmost popup has preference (maybe error, then check) else if (ScreenPopupError <> nil) and (ScreenPopupError.Visible) then - done := not ScreenPopupError.ParseInput(Event.key.keysym.sym, Event.key.keysym.unicode, True) + Done := not ScreenPopupError.ParseInput(Event.key.keysym.sym, Event.key.keysym.unicode, true) else if (ScreenPopupCheck <> nil) and (ScreenPopupCheck.Visible) then - done := not ScreenPopupCheck.ParseInput(Event.key.keysym.sym, Event.key.keysym.unicode, True) + Done := not ScreenPopupCheck.ParseInput(Event.key.keysym.sym, Event.key.keysym.unicode, true) else begin // check if screen wants to exit - done := not Display.CurrentScreen^.ParseInput(Event.key.keysym.sym, Event.key.keysym.unicode, True); + Done := not Display.CurrentScreen^.ParseInput(Event.key.keysym.sym, Event.key.keysym.unicode, true); // if screen wants to exit - if done then + if Done then begin // if question option is enabled then show exit popup if (Ini.AskbeforeDel = 1) then @@ -567,7 +479,7 @@ begin begin Display.Fade := 0; Display.NextScreenWithCheck := nil; - Display.CheckOK := True; + Display.CheckOK := true; end; end; @@ -604,573 +516,4 @@ begin SDL_PushEvent(@Event); end; -function GetTimeForBeats(BPM, Beats: real): real; -begin - Result := 60 / BPM * Beats; -end; - -function GetBeats(BPM, msTime: real): real; -begin - Result := BPM * msTime / 60; -end; - -procedure GetMidBeatSub(BPMNum: integer; var Time: real; var CurBeat: real); -var - NewTime: real; -begin - if High(CurrentSong.BPM) = BPMNum then - begin - // last BPM - CurBeat := CurrentSong.BPM[BPMNum].StartBeat + GetBeats(CurrentSong.BPM[BPMNum].BPM, Time); - Time := 0; - end - else - begin - // not last BPM - // count how much time is it for start of the new BPM and store it in NewTime - NewTime := GetTimeForBeats(CurrentSong.BPM[BPMNum].BPM, CurrentSong.BPM[BPMNum+1].StartBeat - CurrentSong.BPM[BPMNum].StartBeat); - - // compare it to remaining time - if (Time - NewTime) > 0 then - begin - // there is still remaining time - CurBeat := CurrentSong.BPM[BPMNum].StartBeat; - Time := Time - NewTime; - end - else - begin - // there is no remaining time - CurBeat := CurrentSong.BPM[BPMNum].StartBeat + GetBeats(CurrentSong.BPM[BPMNum].BPM, Time); - Time := 0; - end; // if - end; // if -end; - -function GetMidBeat(Time: real): real; -var - CurBeat: real; - CurBPM: integer; -begin - // static BPM - if Length(CurrentSong.BPM) = 1 then - begin - Result := Time * CurrentSong.BPM[0].BPM / 60; - end - // variable BPM - else if Length(CurrentSong.BPM) > 1 then - begin - CurBeat := 0; - CurBPM := 0; - while (Time > 0) do - begin - GetMidBeatSub(CurBPM, Time, CurBeat); - Inc(CurBPM); - end; - - Result := CurBeat; - end - // invalid BPM - else - begin - Result := 0; - end; -end; - -function GetTimeFromBeat(Beat: integer): real; -var - CurBPM: integer; -begin - // static BPM - if Length(CurrentSong.BPM) = 1 then - begin - Result := CurrentSong.GAP / 1000 + Beat * 60 / CurrentSong.BPM[0].BPM; - end - // variable BPM - else if Length(CurrentSong.BPM) > 1 then - begin - Result := CurrentSong.GAP / 1000; - CurBPM := 0; - while (CurBPM <= High(CurrentSong.BPM)) and - (Beat > CurrentSong.BPM[CurBPM].StartBeat) do - begin - if (CurBPM < High(CurrentSong.BPM)) and - (Beat >= CurrentSong.BPM[CurBPM+1].StartBeat) then - begin - // full range - Result := Result + (60 / CurrentSong.BPM[CurBPM].BPM) * - (CurrentSong.BPM[CurBPM+1].StartBeat - CurrentSong.BPM[CurBPM].StartBeat); - end; - - if (CurBPM = High(CurrentSong.BPM)) or - (Beat < CurrentSong.BPM[CurBPM+1].StartBeat) then - begin - // in the middle - Result := Result + (60 / CurrentSong.BPM[CurBPM].BPM) * - (Beat - CurrentSong.BPM[CurBPM].StartBeat); - end; - Inc(CurBPM); - end; - - { - while (Time > 0) do - begin - GetMidBeatSub(CurBPM, Time, CurBeat); - Inc(CurBPM); - end; - } - end - // invalid BPM - else - begin - Result := 0; - end; -end; - -procedure Sing(Screen: TScreenSing); -var - Count: integer; - CountGr: integer; - CP: integer; - N: integer; -begin - LyricsState.UpdateBeats(); - - // sentences routines - for CountGr := 0 to 0 do //High(Lines) - begin; - CP := CountGr; - // old parts - LyricsState.OldLine := Lines[CP].Current; - - // choose current parts - for Count := 0 to Lines[CP].High do - begin - if LyricsState.CurrentBeat >= Lines[CP].Line[Count].Start then - Lines[CP].Current := Count; - end; - - // clean player note if there is a new line - // (optimization on halfbeat time) - if Lines[CP].Current <> LyricsState.OldLine then - NewSentence(Screen); - - end; // for CountGr - - // make some operations on clicks - if {(LyricsState.CurrentBeatC >= 0) and }(LyricsState.OldBeatC <> LyricsState.CurrentBeatC) then - NewBeatClick(Screen); - - // make some operations when detecting new voice pitch - if (LyricsState.CurrentBeatD >= 0) and (LyricsState.OldBeatD <> LyricsState.CurrentBeatD) then - NewBeatDetect(Screen); -end; - -procedure NewSentence(Screen: TScreenSing); -var - i: Integer; -begin - // clean note of player - for i := 0 to High(Player) do - begin - Player[i].LengthNote := 0; - Player[i].HighNote := -1; - SetLength(Player[i].Note, 0); - end; - - // on sentence change... - Screen.onSentenceChange(Lines[0].Current); -end; - -procedure NewBeatClick; -var - Count: integer; -begin - // beat click - if ((Ini.BeatClick = 1) and - ((LyricsState.CurrentBeatC + Lines[0].Resolution + Lines[0].NotesGAP) mod Lines[0].Resolution = 0)) then - begin - AudioPlayback.PlaySound(SoundLib.Click); - end; - - for Count := 0 to Lines[0].Line[Lines[0].Current].HighNote do - begin - if (Lines[0].Line[Lines[0].Current].Note[Count].Start = LyricsState.CurrentBeatC) then - begin - // click assist - if Ini.ClickAssist = 1 then - AudioPlayback.PlaySound(SoundLib.Click); - - // drum machine - (* - TempBeat := LyricsState.CurrentBeat;// + 2; - if (TempBeat mod 8 = 0) then Music.PlayDrum; - if (TempBeat mod 8 = 4) then Music.PlayClap; - //if (TempBeat mod 4 = 2) then Music.PlayHihat; - if (TempBeat mod 4 <> 0) then Music.PlayHihat; - *) - end; - end; -end; - -procedure NewBeatDetect(Screen: TScreenSing); -begin - NewNote(Screen); -end; - -procedure NewNote(Screen: TScreenSing); -var - LineFragmentIndex: integer; - CurrentLineFragment: PLineFragment; - PlayerIndex: integer; - CurrentSound: TCaptureBuffer; - CurrentPlayer: PPlayer; - LastPlayerNote: PPlayerNote; - Line: PLine; - SentenceIndex: integer; - SentenceMin: integer; - SentenceMax: integer; - SentenceDetected: integer; // sentence of detected note - NoteAvailable: boolean; - NewNote: boolean; - Range: integer; - NoteHit: boolean; - MaxSongPoints: integer; // max. points for the song (without line bonus) - MaxLinePoints: Real; // max. points for the current line -begin - // TODO: add duet mode support - // use Lines[LineSetIndex] with LineSetIndex depending on the current player - - // count min and max sentence range for checking (detection is delayed to the notes we see on the screen) - SentenceMin := Lines[0].Current-1; - if (SentenceMin < 0) then - SentenceMin := 0; - SentenceMax := Lines[0].Current; - - // check for an active note at the current time defined in the lyrics - NoteAvailable := false; - SentenceDetected := SentenceMin; - for SentenceIndex := SentenceMin to SentenceMax do - begin - Line := @Lines[0].Line[SentenceIndex]; - for LineFragmentIndex := 0 to Line.HighNote do - begin - CurrentLineFragment := @Line.Note[LineFragmentIndex]; - // check if line is active - if ((CurrentLineFragment.Start <= LyricsState.CurrentBeatD) and - (CurrentLineFragment.Start + CurrentLineFragment.Length-1 >= LyricsState.CurrentBeatD)) and - (CurrentLineFragment.NoteType <> ntFreestyle) and // but ignore FreeStyle notes - (CurrentLineFragment.Length > 0) then // and make sure the note lengths is at least 1 - begin - SentenceDetected := SentenceIndex; - NoteAvailable := true; - Break; - end; - end; - // TODO: break here, if NoteAvailable is true? We would then use the first instead - // of the last note matching the current beat if notes overlap. But notes - // should not overlap at all. - //if (NoteAvailable) then - // Break; - end; - - // analyze player signals - for PlayerIndex := 0 to PlayersPlay-1 do - begin - CurrentPlayer := @Player[PlayerIndex]; - CurrentSound := AudioInputProcessor.Sound[PlayerIndex]; - - // At the beginning of the song there is no previous note - if (Length(CurrentPlayer.Note) > 0) then - LastPlayerNote := @CurrentPlayer.Note[CurrentPlayer.HighNote] - else - LastPlayerNote := nil; - - // analyze buffer - CurrentSound.AnalyzeBuffer; - - // add some noise - // TODO: do we need this? - //LyricsState.Tone := LyricsState.Tone + Round(Random(3)) - 1; - - // add note if possible - if (CurrentSound.ToneValid and NoteAvailable) then - begin - Line := @Lines[0].Line[SentenceDetected]; - - // process until last note - for LineFragmentIndex := 0 to Line.HighNote do - begin - CurrentLineFragment := @Line.Note[LineFragmentIndex]; - if (CurrentLineFragment.Start <= LyricsState.OldBeatD+1) and - (CurrentLineFragment.Start + CurrentLineFragment.Length > LyricsState.OldBeatD+1) then - begin - // compare notes (from song-file and from player) - - // move players tone to proper octave - while (CurrentSound.Tone - CurrentLineFragment.Tone > 6) do - CurrentSound.Tone := CurrentSound.Tone - 12; - - while (CurrentSound.Tone - CurrentLineFragment.Tone < -6) do - CurrentSound.Tone := CurrentSound.Tone + 12; - - // half size notes patch - NoteHit := false; - - //if Ini.Difficulty = 0 then Range := 2; - //if Ini.Difficulty = 1 then Range := 1; - //if Ini.Difficulty = 2 then Range := 0; - Range := 2 - Ini.Difficulty; - - // check if the player hit the correct tone within the tolerated range - if (Abs(CurrentLineFragment.Tone - CurrentSound.Tone) <= Range) then - begin - // adjust the players tone to the correct one - // TODO: do we need to do this? - CurrentSound.Tone := CurrentLineFragment.Tone; - - // half size notes patch - NoteHit := true; - - if (Ini.LineBonus > 0) then - MaxSongPoints := MAX_SONG_SCORE - MAX_SONG_LINE_BONUS - else - MaxSongPoints := MAX_SONG_SCORE; - - // Note: ScoreValue is the sum of all note values of the song - MaxLinePoints := MaxSongPoints / Lines[0].ScoreValue; - - // FIXME: is this correct? Why do we add the points for a whole line - // if just one note is correct? - case CurrentLineFragment.NoteType of - ntNormal: CurrentPlayer.Score := CurrentPlayer.Score + MaxLinePoints; - ntGolden: CurrentPlayer.ScoreGolden := CurrentPlayer.ScoreGolden + MaxLinePoints; - end; - - CurrentPlayer.ScoreInt := Floor(CurrentPlayer.Score / 10) * 10; - CurrentPlayer.ScoreGoldenInt := Floor(CurrentPlayer.ScoreGolden / 10) * 10; - - CurrentPlayer.ScoreTotalInt := CurrentPlayer.ScoreInt + - CurrentPlayer.ScoreGoldenInt + - CurrentPlayer.ScoreLineInt; - end; - - end; // operation - end; // for - - // check if we have to add a new note or extend the note's length - if (SentenceDetected = SentenceMax) then - begin - // we will add a new note - NewNote := true; - - // if previous note (if any) was the same, extend prrevious note - if ((CurrentPlayer.LengthNote > 0) and - (LastPlayerNote <> nil) and - (LastPlayerNote.Tone = CurrentSound.Tone) and - ((LastPlayerNote.Start + LastPlayerNote.Length) = LyricsState.CurrentBeatD)) then - begin - NewNote := false; - end; - - // if is not as new note to control - for LineFragmentIndex := 0 to Line.HighNote do - begin - if (Line.Note[LineFragmentIndex].Start = LyricsState.CurrentBeatD) then - NewNote := true; - end; - - // add new note - if NewNote then - begin - // new note - Inc(CurrentPlayer.LengthNote); - Inc(CurrentPlayer.HighNote); - SetLength(CurrentPlayer.Note, CurrentPlayer.LengthNote); - - // update player's last note - LastPlayerNote := @CurrentPlayer.Note[CurrentPlayer.HighNote]; - with LastPlayerNote^ do - begin - Start := LyricsState.CurrentBeatD; - Length := 1; - Tone := CurrentSound.Tone; // Tone || ToneAbs - Detect := LyricsState.MidBeat; - Hit := NoteHit; // half note patch - end; - end - else - begin - // extend note length - if (LastPlayerNote <> nil) then - Inc(LastPlayerNote.Length); - end; - - // check for perfect note and then lit the star (on Draw) - for LineFragmentIndex := 0 to Line.HighNote do - begin - CurrentLineFragment := @Line.Note[LineFragmentIndex]; - if (CurrentLineFragment.Start = LastPlayerNote.Start) and - (CurrentLineFragment.Length = LastPlayerNote.Length) and - (CurrentLineFragment.Tone = LastPlayerNote.Tone) then - begin - LastPlayerNote.Perfect := true; - end; - end; - end; // if SentenceDetected = SentenceMax - - end; // if Detected - end; // for PlayerIndex - - //Log.LogStatus('EndBeat', 'NewBeat'); - - // on sentence end -> for LineBonus and display of SingBar (rating pop-up) - if (SentenceDetected >= Low(Lines[0].Line)) and - (SentenceDetected <= High(Lines[0].Line)) then - begin - Line := @Lines[0].Line[SentenceDetected]; - CurrentLineFragment := @Line.Note[Line.HighNote]; - if ((CurrentLineFragment.Start + CurrentLineFragment.Length - 1) = LyricsState.CurrentBeatD) then - begin - if assigned(Screen) then - Screen.OnSentenceEnd(SentenceDetected); - end; - end; - -end; - -procedure ClearScores(PlayerNum: integer); -begin - with Player[PlayerNum] do - begin - Score := 0; - ScoreLine := 0; - ScoreGolden := 0; - - ScoreInt := 0; - ScoreLineInt := 0; - ScoreGoldenInt:= 0; - ScoreTotalInt := 0; - - ScoreLast := 0; - - LastSentencePerfect := False; - end; -end; - -procedure AddSpecialPath(var PathList: TStringList; const Path: string); -var - I: integer; - PathAbs, OldPathAbs: string; -begin - if (PathList = nil) then - PathList := TStringList.Create; - - if (Path = '') or not ForceDirectories(Path) then - Exit; - - PathAbs := IncludeTrailingPathDelimiter(ExpandFileName(Path)); - - // check if path or a part of the path was already added - for I := 0 to PathList.Count-1 do - begin - OldPathAbs := IncludeTrailingPathDelimiter(ExpandFileName(PathList[I])); - // check if the new directory is a sub-directory of a previously added one. - // This is also true, if both paths point to the same directories. - if (AnsiStartsText(OldPathAbs, PathAbs)) then - begin - // ignore the new path - Exit; - end; - - // check if a previously added directory is a sub-directory of the new one. - if (AnsiStartsText(PathAbs, OldPathAbs)) then - begin - // replace the old with the new one. - PathList[I] := PathAbs; - Exit; - end; - end; - - PathList.Add(PathAbs); -end; - -procedure AddSongPath(const Path: string); -begin - AddSpecialPath(SongPaths, Path); -end; - -procedure AddCoverPath(const Path: string); -begin - AddSpecialPath(CoverPaths, Path); -end; - -(** - * Initialize a path variable - * After setting paths, make sure that paths exist - *) -function FindPath(out PathResult: string; const RequestedPath: string; NeedsWritePermission: boolean): boolean; -begin - Result := false; - - if (RequestedPath = '') then - Exit; - - // Make sure the directory exists - if (not ForceDirectories(RequestedPath)) then - begin - PathResult := ''; - Exit; - end; - - PathResult := IncludeTrailingPathDelimiter(RequestedPath); - - if (NeedsWritePermission) and - (FileIsReadOnly(RequestedPath)) then - begin - Exit; - end; - - Result := true; -end; - -(** - * Function sets all absolute paths e.g. song path and makes sure the directorys exist - *) -procedure InitializePaths; -begin - // Log directory (must be writable) - if (not FindPath(LogPath, Platform.GetLogPath, true)) then - begin - Log.FileOutputEnabled := false; - Log.LogWarn('Log directory "'+ Platform.GetLogPath +'" not available', 'InitializePaths'); - end; - - FindPath(SoundPath, Platform.GetGameSharedPath + 'sounds', false); - FindPath(ThemePath, Platform.GetGameSharedPath + 'themes', false); - FindPath(SkinsPath, Platform.GetGameSharedPath + 'themes', false); - FindPath(LanguagesPath, Platform.GetGameSharedPath + 'languages', false); - FindPath(PluginPath, Platform.GetGameSharedPath + 'plugins', false); - FindPath(VisualsPath, Platform.GetGameSharedPath + 'visuals', false); - FindPath(FontPath, Platform.GetGameSharedPath + 'fonts', false); - FindPath(ResourcesPath, Platform.GetGameSharedPath + 'resources', false); - - // Playlists are not shared as we need one directory to write too - FindPath(PlaylistPath, Platform.GetGameUserPath + 'playlists', true); - - // Screenshot directory (must be writable) - if (not FindPath(ScreenshotsPath, Platform.GetGameUserPath + 'screenshots', true)) then - begin - Log.LogWarn('Screenshot directory "'+ Platform.GetGameUserPath +'" not available', 'InitializePaths'); - end; - - // Add song paths - AddSongPath(Params.SongPath); - AddSongPath(Platform.GetGameSharedPath + 'songs'); - AddSongPath(Platform.GetGameUserPath + 'songs'); - - // Add category cover paths - AddCoverPath(Platform.GetGameSharedPath + 'covers'); - AddCoverPath(Platform.GetGameUserPath + 'covers'); -end; - end. diff --git a/unicode/src/base/UMusic.pas b/unicode/src/base/UMusic.pas index 70e8d63c..19c3b942 100644 --- a/unicode/src/base/UMusic.pas +++ b/unicode/src/base/UMusic.pas @@ -35,11 +35,21 @@ interface uses UTime, + SysUtils, Classes; type TNoteType = (ntFreestyle, ntNormal, ntGolden); +const + // ScoreFactor defines how a notehit of a specified notetype is + // measured in comparison to the other types + // 0 means this notetype is not rated at all + // 2 means a hit of this notetype will be rated w/ twice as much + // points as a hit of a notetype w/ ScoreFactor 1 + ScoreFactor: array[TNoteType] of integer = (0, 1, 2); + +type (** * TLineFragment represents a fragment of a lyrics line. * This is a text-fragment (e.g. a syllable) assigned to a note pitch, @@ -63,7 +73,7 @@ type TLine = record Start: integer; // the start beat of this line (<> start beat of the first note of this line) Lyric: UTF8String; - LyricWidth: real; // @deprecated: width of the line in pixels. + //LyricWidth: real; // @deprecated: width of the line in pixels. // Do not use this as the width is not correct. // Use TLyricsEngine.GetUpperLine().Width instead. End_: integer; @@ -81,7 +91,7 @@ type *) TLines = record Current: integer; // for drawing of current line - High: integer; // (= High(Line)?) + High: integer; // = High(Line)! Number: integer; Resolution: integer; NotesGAP: integer; @@ -212,12 +222,12 @@ type TSoundEffect = class public EngineData: Pointer; // can be used for engine-specific data - procedure Callback(Buffer: PChar; BufSize: integer); virtual; abstract; + procedure Callback(Buffer: PByteArray; BufSize: integer); virtual; abstract; end; TVoiceRemoval = class(TSoundEffect) public - procedure Callback(Buffer: PChar; BufSize: integer); override; + procedure Callback(Buffer: PByteArray; BufSize: integer); override; end; type @@ -262,7 +272,7 @@ type function IsEOF(): boolean; virtual; abstract; function IsError(): boolean; virtual; abstract; public - function ReadData(Buffer: PChar; BufferSize: integer): integer; virtual; abstract; + function ReadData(Buffer: PByteArray; BufferSize: integer): integer; virtual; abstract; property EOF: boolean read IsEOF; property Error: boolean read IsError; @@ -292,7 +302,7 @@ type function GetVolume(): single; virtual; abstract; procedure SetVolume(Volume: single); virtual; abstract; function Synchronize(BufferSize: integer; FormatInfo: TAudioFormatInfo): integer; - procedure FillBufferWithFrame(Buffer: PChar; BufferSize: integer; Frame: PChar; FrameSize: integer); + procedure FillBufferWithFrame(Buffer: PByteArray; BufferSize: integer; Frame: PByteArray; FrameSize: integer); public (** * Opens a SourceStream for playback. @@ -335,7 +345,7 @@ type function Open(ChannelMap: integer; FormatInfo: TAudioFormatInfo): boolean; virtual; procedure Close(); override; - procedure WriteData(Buffer: PChar; BufferSize: integer); virtual; abstract; + procedure WriteData(Buffer: PByteArray; BufferSize: integer); virtual; abstract; function GetAudioFormatInfo(): TAudioFormatInfo; override; function GetLength(): real; override; @@ -468,7 +478,7 @@ type * input-buffer bytes used. * Returns the number of bytes written to the output-buffer or -1 if an error occured. *) - function Convert(InputBuffer: PChar; OutputBuffer: PChar; var InputSize: integer): integer; virtual; abstract; + function Convert(InputBuffer: PByteArray; OutputBuffer: PByteArray; var InputSize: integer): integer; virtual; abstract; (** * Destination/Source size ratio @@ -561,13 +571,13 @@ procedure DumpMediaInterfaces(); implementation uses - sysutils, math, UIni, - UMain, + UNote, UCommandLine, URecord, - ULog; + ULog, + UPath; var DefaultVideoPlayback : IVideoPlayback; @@ -942,7 +952,7 @@ end; { TVoiceRemoval } -procedure TVoiceRemoval.Callback(Buffer: PChar; BufSize: integer); +procedure TVoiceRemoval.Callback(Buffer: PByteArray; BufSize: integer); var FrameIndex, FrameSize: integer; Value: integer; @@ -1180,7 +1190,7 @@ end; (* * Fills a buffer with copies of the given frame or with 0 if frame. *) -procedure TAudioPlaybackStream.FillBufferWithFrame(Buffer: PChar; BufferSize: integer; Frame: PChar; FrameSize: integer); +procedure TAudioPlaybackStream.FillBufferWithFrame(Buffer: PByteArray; BufferSize: integer; Frame: PByteArray; FrameSize: integer); var i: integer; FrameCopyCount: integer; diff --git a/unicode/src/base/UNote.pas b/unicode/src/base/UNote.pas new file mode 100644 index 00000000..5e70bfe1 --- /dev/null +++ b/unicode/src/base/UNote.pas @@ -0,0 +1,593 @@ +{* UltraStar Deluxe - Karaoke Game + * + * UltraStar Deluxe is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + * + * $URL: https://ultrastardx.svn.sourceforge.net/svnroot/ultrastardx/trunk/src/base/UNote.pas $ + * $Id: UNote.pas 1626 2009-03-07 19:53:00Z k-m_schindler $ + *} + +unit UNote; + +interface + +{$IFDEF FPC} + {$MODE Delphi} +{$ENDIF} + +{$I switches.inc} + +uses + SysUtils, + Classes, + SDL, + UMusic, + URecord, + UTime, + UDisplay, + UIni, + ULog, + ULyrics, + UScreenSing, + USong, + gl; + +type + PPLayerNote = ^TPlayerNote; + TPlayerNote = record + Start: integer; + Length: integer; + Detect: real; // accurate place, detected in the note + Tone: real; + Perfect: boolean; // true if the note matches the original one, light the star + Hit: boolean; // true if the note hits the line + end; + + PPLayer = ^TPlayer; + TPlayer = record + Name: string; + + // Index in Teaminfo record + TeamID: byte; + PlayerID: byte; + + // Scores + Score: real; + ScoreLine: real; + ScoreGolden: real; + + ScoreInt: integer; + ScoreLineInt: integer; + ScoreGoldenInt: integer; + ScoreTotalInt: integer; + + // LineBonus + ScoreLast: real; // Last Line Score + + // PerfectLineTwinkle (effect) + LastSentencePerfect: boolean; + + HighNote: integer; // index of last note (= High(Note)?) + LengthNote: integer; // number of notes (= Length(Note)?). + Note: array of TPlayerNote; + end; + +var + + // player and music info + Player: array of TPlayer; + PlayersPlay: integer; + + CurrentSong: TSong; + +const + MAX_SONG_SCORE = 10000; // max. achievable points per song + MAX_SONG_LINE_BONUS = 1000; // max. achievable line bonus per song + +procedure Sing(Screen: TScreenSing); +procedure NewSentence(Screen: TScreenSing); +procedure NewBeatClick(Screen: TScreenSing); // executed when on then new beat for click +procedure NewBeatDetect(Screen: TScreenSing); // executed when on then new beat for detection +procedure NewNote(Screen: TScreenSing); // detect note +function GetMidBeat(Time: real): real; +function GetTimeFromBeat(Beat: integer): real; + +implementation + +uses + Math, + StrUtils, + USongs, + UJoystick, + UCommandLine, + ULanguage, + //SDL_ttf, + USkins, + UCovers, + UCatCovers, + UDataBase, + UPlaylist, + UDLLManager, + UParty, + UConfig, + UCore, + UCommon, + UGraphic, + UGraphicClasses, + UPath, + UPluginDefs, + UPlatform, + UThemes; + +function GetTimeForBeats(BPM, Beats: real): real; +begin + Result := 60 / BPM * Beats; +end; + +function GetBeats(BPM, msTime: real): real; +begin + Result := BPM * msTime / 60; +end; + +procedure GetMidBeatSub(BPMNum: integer; var Time: real; var CurBeat: real); +var + NewTime: real; +begin + if High(CurrentSong.BPM) = BPMNum then + begin + // last BPM + CurBeat := CurrentSong.BPM[BPMNum].StartBeat + GetBeats(CurrentSong.BPM[BPMNum].BPM, Time); + Time := 0; + end + else + begin + // not last BPM + // count how much time is it for start of the new BPM and store it in NewTime + NewTime := GetTimeForBeats(CurrentSong.BPM[BPMNum].BPM, CurrentSong.BPM[BPMNum+1].StartBeat - CurrentSong.BPM[BPMNum].StartBeat); + + // compare it to remaining time + if (Time - NewTime) > 0 then + begin + // there is still remaining time + CurBeat := CurrentSong.BPM[BPMNum].StartBeat; + Time := Time - NewTime; + end + else + begin + // there is no remaining time + CurBeat := CurrentSong.BPM[BPMNum].StartBeat + GetBeats(CurrentSong.BPM[BPMNum].BPM, Time); + Time := 0; + end; // if + end; // if +end; + +function GetMidBeat(Time: real): real; +var + CurBeat: real; + CurBPM: integer; +begin + // static BPM + if Length(CurrentSong.BPM) = 1 then + begin + Result := Time * CurrentSong.BPM[0].BPM / 60; + end + // variable BPM + else if Length(CurrentSong.BPM) > 1 then + begin + CurBeat := 0; + CurBPM := 0; + while (Time > 0) do + begin + GetMidBeatSub(CurBPM, Time, CurBeat); + Inc(CurBPM); + end; + + Result := CurBeat; + end + // invalid BPM + else + begin + Result := 0; + end; +end; + +function GetTimeFromBeat(Beat: integer): real; +var + CurBPM: integer; +begin + // static BPM + if Length(CurrentSong.BPM) = 1 then + begin + Result := CurrentSong.GAP / 1000 + Beat * 60 / CurrentSong.BPM[0].BPM; + end + // variable BPM + else if Length(CurrentSong.BPM) > 1 then + begin + Result := CurrentSong.GAP / 1000; + CurBPM := 0; + while (CurBPM <= High(CurrentSong.BPM)) and + (Beat > CurrentSong.BPM[CurBPM].StartBeat) do + begin + if (CurBPM < High(CurrentSong.BPM)) and + (Beat >= CurrentSong.BPM[CurBPM+1].StartBeat) then + begin + // full range + Result := Result + (60 / CurrentSong.BPM[CurBPM].BPM) * + (CurrentSong.BPM[CurBPM+1].StartBeat - CurrentSong.BPM[CurBPM].StartBeat); + end; + + if (CurBPM = High(CurrentSong.BPM)) or + (Beat < CurrentSong.BPM[CurBPM+1].StartBeat) then + begin + // in the middle + Result := Result + (60 / CurrentSong.BPM[CurBPM].BPM) * + (Beat - CurrentSong.BPM[CurBPM].StartBeat); + end; + Inc(CurBPM); + end; + + { + while (Time > 0) do + begin + GetMidBeatSub(CurBPM, Time, CurBeat); + Inc(CurBPM); + end; + } + end + // invalid BPM + else + begin + Result := 0; + end; +end; + +procedure Sing(Screen: TScreenSing); +var + Count: integer; + CountGr: integer; + CP: integer; +begin + LyricsState.UpdateBeats(); + + // sentences routines + for CountGr := 0 to 0 do //High(Lines) + begin; + CP := CountGr; + // old parts + LyricsState.OldLine := Lines[CP].Current; + + // choose current parts + for Count := 0 to Lines[CP].High do + begin + if LyricsState.CurrentBeat >= Lines[CP].Line[Count].Start then + Lines[CP].Current := Count; + end; + + // clean player note if there is a new line + // (optimization on halfbeat time) + if Lines[CP].Current <> LyricsState.OldLine then + NewSentence(Screen); + + end; // for CountGr + + // make some operations on clicks + if {(LyricsState.CurrentBeatC >= 0) and }(LyricsState.OldBeatC <> LyricsState.CurrentBeatC) then + NewBeatClick(Screen); + + // make some operations when detecting new voice pitch + if (LyricsState.CurrentBeatD >= 0) and (LyricsState.OldBeatD <> LyricsState.CurrentBeatD) then + NewBeatDetect(Screen); +end; + +procedure NewSentence(Screen: TScreenSing); +var + i: integer; +begin + // clean note of player + for i := 0 to High(Player) do + begin + Player[i].LengthNote := 0; + Player[i].HighNote := -1; + SetLength(Player[i].Note, 0); + end; + + // on sentence change... + Screen.onSentenceChange(Lines[0].Current); +end; + +procedure NewBeatClick; +var + Count: integer; +begin + // beat click + if ((Ini.BeatClick = 1) and + ((LyricsState.CurrentBeatC + Lines[0].Resolution + Lines[0].NotesGAP) mod Lines[0].Resolution = 0)) then + begin + AudioPlayback.PlaySound(SoundLib.Click); + end; + + for Count := 0 to Lines[0].Line[Lines[0].Current].HighNote do + begin + if (Lines[0].Line[Lines[0].Current].Note[Count].Start = LyricsState.CurrentBeatC) then + begin + // click assist + if Ini.ClickAssist = 1 then + AudioPlayback.PlaySound(SoundLib.Click); + + // drum machine + (* + TempBeat := LyricsState.CurrentBeat; // + 2; + if (TempBeat mod 8 = 0) then Music.PlayDrum; + if (TempBeat mod 8 = 4) then Music.PlayClap; + //if (TempBeat mod 4 = 2) then Music.PlayHihat; + if (TempBeat mod 4 <> 0) then Music.PlayHihat; + *) + end; + end; +end; + +procedure NewBeatDetect(Screen: TScreenSing); +begin + NewNote(Screen); +end; + +procedure NewNote(Screen: TScreenSing); +var + LineFragmentIndex: integer; + CurrentLineFragment: PLineFragment; + PlayerIndex: integer; + CurrentSound: TCaptureBuffer; + CurrentPlayer: PPlayer; + LastPlayerNote: PPlayerNote; + Line: PLine; + SentenceIndex: integer; + SentenceMin: integer; + SentenceMax: integer; + SentenceDetected: integer; // sentence of detected note + NoteAvailable: boolean; + NewNote: boolean; + Range: integer; + NoteHit: boolean; + MaxSongPoints: integer; // max. points for the song (without line bonus) + CurNotePoints: real; // Points for the cur. Note (PointsperNote * ScoreFactor[CurNote]) +begin + // TODO: add duet mode support + // use Lines[LineSetIndex] with LineSetIndex depending on the current player + + // count min and max sentence range for checking + // (detection is delayed to the notes we see on the screen) + SentenceMin := Lines[0].Current-1; + if (SentenceMin < 0) then + SentenceMin := 0; + SentenceMax := Lines[0].Current; + + // check for an active note at the current time defined in the lyrics + NoteAvailable := false; + SentenceDetected := SentenceMin; + for SentenceIndex := SentenceMin to SentenceMax do + begin + Line := @Lines[0].Line[SentenceIndex]; + for LineFragmentIndex := 0 to Line.HighNote do + begin + CurrentLineFragment := @Line.Note[LineFragmentIndex]; + // check if line is active + if ((CurrentLineFragment.Start <= LyricsState.CurrentBeatD) and + (CurrentLineFragment.Start + CurrentLineFragment.Length-1 >= LyricsState.CurrentBeatD)) and + (CurrentLineFragment.NoteType <> ntFreestyle) and // but ignore FreeStyle notes + (CurrentLineFragment.Length > 0) then // and make sure the note length is at least 1 + begin + SentenceDetected := SentenceIndex; + NoteAvailable := true; + Break; + end; + end; + // TODO: break here, if NoteAvailable is true? We would then use the first instead + // of the last note matching the current beat if notes overlap. But notes + // should not overlap at all. + // if (NoteAvailable) then + // Break; + end; + + // analyze player signals + for PlayerIndex := 0 to PlayersPlay-1 do + begin + CurrentPlayer := @Player[PlayerIndex]; + CurrentSound := AudioInputProcessor.Sound[PlayerIndex]; + + // at the beginning of the song there is no previous note + if (Length(CurrentPlayer.Note) > 0) then + LastPlayerNote := @CurrentPlayer.Note[CurrentPlayer.HighNote] + else + LastPlayerNote := nil; + + // analyze buffer + CurrentSound.AnalyzeBuffer; + + // add some noise + // TODO: do we need this? + //LyricsState.Tone := LyricsState.Tone + Round(Random(3)) - 1; + + // add note if possible + if (CurrentSound.ToneValid and NoteAvailable) then + begin + Line := @Lines[0].Line[SentenceDetected]; + + // process until last note + for LineFragmentIndex := 0 to Line.HighNote do + begin + CurrentLineFragment := @Line.Note[LineFragmentIndex]; + if (CurrentLineFragment.Start <= LyricsState.OldBeatD+1) and + (CurrentLineFragment.Start + CurrentLineFragment.Length > LyricsState.OldBeatD+1) then + begin + // compare notes (from song-file and from player) + + // move players tone to proper octave + while (CurrentSound.Tone - CurrentLineFragment.Tone > 6) do + CurrentSound.Tone := CurrentSound.Tone - 12; + + while (CurrentSound.Tone - CurrentLineFragment.Tone < -6) do + CurrentSound.Tone := CurrentSound.Tone + 12; + + // half size notes patch + NoteHit := false; + + // if Ini.Difficulty = 0 then Range := 2; + // if Ini.Difficulty = 1 then Range := 1; + // if Ini.Difficulty = 2 then Range := 0; + Range := 2 - Ini.Difficulty; + + // check if the player hit the correct tone within the tolerated range + if (Abs(CurrentLineFragment.Tone - CurrentSound.Tone) <= Range) then + begin + // adjust the players tone to the correct one + // TODO: do we need to do this? + // Philipp: I think we do, at least when we draw the notes. + // Otherwise the notehit thing would be shifted to the + // correct unhit note. I think this will look kind of strange. + CurrentSound.Tone := CurrentLineFragment.Tone; + + // half size notes patch + NoteHit := true; + + if (Ini.LineBonus > 0) then + MaxSongPoints := MAX_SONG_SCORE - MAX_SONG_LINE_BONUS + else + MaxSongPoints := MAX_SONG_SCORE; + + // Note: ScoreValue is the sum of all note values of the song + // (MaxSongPoints / ScoreValue) is the points that a player + // gets for a hit of one beat of a normal note + // CurNotePoints is the amount of points that is meassured + // for a hit of the note per full beat + CurNotePoints := (MaxSongPoints / Lines[0].ScoreValue) * ScoreFactor[CurrentLineFragment.NoteType]; + + case CurrentLineFragment.NoteType of + ntNormal: CurrentPlayer.Score := CurrentPlayer.Score + CurNotePoints; + ntGolden: CurrentPlayer.ScoreGolden := CurrentPlayer.ScoreGolden + CurNotePoints; + end; + + // a problem if we use floor instead of round is that a score of + // 10000 points is only possible if the last digit of the total points + // for golden and normal notes is 0. + // if we use round, the max score is 10000 for most songs + // but a score of 10010 is possible if the last digit of the total + // points for golden and normal notes is 5 + // the best solution is to use round for one of these scores + // and round the other score in the opposite direction + // so we assure that the highest possible score is 10000 in every case. + CurrentPlayer.ScoreInt := round(CurrentPlayer.Score / 10) * 10; + + if (CurrentPlayer.ScoreInt < CurrentPlayer.Score) then + //normal score is floored so we have to ceil golden notes score + CurrentPlayer.ScoreGoldenInt := ceil(CurrentPlayer.ScoreGolden / 10) * 10 + else + //normal score is ceiled so we have to floor golden notes score + CurrentPlayer.ScoreGoldenInt := floor(CurrentPlayer.ScoreGolden / 10) * 10; + + + CurrentPlayer.ScoreTotalInt := CurrentPlayer.ScoreInt + + CurrentPlayer.ScoreGoldenInt + + CurrentPlayer.ScoreLineInt; + end; + + end; // operation + end; // for + + // check if we have to add a new note or extend the note's length + if (SentenceDetected = SentenceMax) then + begin + // we will add a new note + NewNote := true; + + // if previous note (if any) was the same, extend previous note + if ((CurrentPlayer.LengthNote > 0) and + (LastPlayerNote <> nil) and + (LastPlayerNote.Tone = CurrentSound.Tone) and + ((LastPlayerNote.Start + LastPlayerNote.Length) = LyricsState.CurrentBeatD)) then + begin + NewNote := false; + end; + + // if is not as new note to control + for LineFragmentIndex := 0 to Line.HighNote do + begin + if (Line.Note[LineFragmentIndex].Start = LyricsState.CurrentBeatD) then + NewNote := true; + end; + + // add new note + if NewNote then + begin + // new note + Inc(CurrentPlayer.LengthNote); + Inc(CurrentPlayer.HighNote); + SetLength(CurrentPlayer.Note, CurrentPlayer.LengthNote); + + // update player's last note + LastPlayerNote := @CurrentPlayer.Note[CurrentPlayer.HighNote]; + with LastPlayerNote^ do + begin + Start := LyricsState.CurrentBeatD; + Length := 1; + Tone := CurrentSound.Tone; // Tone || ToneAbs + Detect := LyricsState.MidBeat; + Hit := NoteHit; // half note patch + end; + end + else + begin + // extend note length + if (LastPlayerNote <> nil) then + Inc(LastPlayerNote.Length); + end; + + // check for perfect note and then light the star (on Draw) + for LineFragmentIndex := 0 to Line.HighNote do + begin + CurrentLineFragment := @Line.Note[LineFragmentIndex]; + if (CurrentLineFragment.Start = LastPlayerNote.Start) and + (CurrentLineFragment.Length = LastPlayerNote.Length) and + (CurrentLineFragment.Tone = LastPlayerNote.Tone) then + begin + LastPlayerNote.Perfect := true; + end; + end; + end; // if SentenceDetected = SentenceMax + + end; // if Detected + end; // for PlayerIndex + + //Log.LogStatus('EndBeat', 'NewBeat'); + + // on sentence end -> for LineBonus and display of SingBar (rating pop-up) + if (SentenceDetected >= Low(Lines[0].Line)) and + (SentenceDetected <= High(Lines[0].Line)) then + begin + Line := @Lines[0].Line[SentenceDetected]; + CurrentLineFragment := @Line.Note[Line.HighNote]; + if ((CurrentLineFragment.Start + CurrentLineFragment.Length - 1) = LyricsState.CurrentBeatD) then + begin + if assigned(Screen) then + Screen.OnSentenceEnd(SentenceDetected); + end; + end; + +end; + +end. diff --git a/unicode/src/base/UParty.pas b/unicode/src/base/UParty.pas index 36ab33fb..937aab78 100644 --- a/unicode/src/base/UParty.pas +++ b/unicode/src/base/UParty.pas @@ -39,76 +39,82 @@ uses UPluginDefs; type - ARounds = Array [0..252] of Integer; //0..252 needed for + ARounds = array [0..252] of integer; //0..252 needed for PARounds = ^ARounds; TRoundInfo = record - Modi: Cardinal; - Winner: Byte; + Modi: cardinal; + Winner: byte; end; TeamOrderEntry = record - Teamnum: Byte; - Score: Byte; + Teamnum: byte; + Score: byte; end; - TeamOrderArray = Array[0..5] of Byte; + TeamOrderArray = array[0..5] of byte; TUS_ModiInfoEx = record - Info: TUS_ModiInfo; - Owner: Integer; - TimesPlayed: Byte; //Helper for setting Round Plugins + Info: TUS_ModiInfo; + Owner: integer; + TimesPlayed: byte; //Helper for setting round plugins end; TPartySession = class (TCoreModule) private - bPartyMode: Boolean; //Is this Party or Singleplayer - CurRound: Byte; + bPartyMode: boolean; //Is this party or single player + CurRound: byte; - Modis: Array of TUS_ModiInfoEx; + Modis: array of TUS_ModiInfoEx; Teams: TTeamInfo; - function IsWinner(Player, Winner: Byte): boolean; + function IsWinner(Player, Winner: byte): boolean; procedure GenScores; - function GetRandomPlugin(TeamMode: Boolean): Cardinal; - function GetRandomPlayer(Team: Byte): Byte; + function GetRandomPlugin(TeamMode: boolean): cardinal; + function GetRandomPlayer(Team: byte): byte; public //Teams: TTeamInfo; Rounds: array of TRoundInfo; //TCoreModule methods to inherit - Constructor Create; override; - Procedure Info(const pInfo: PModuleInfo); override; - Function Load: Boolean; override; - Function Init: Boolean; override; - Procedure DeInit; override; - Destructor Destroy; override; + constructor Create; override; + procedure Info(const pInfo: PModuleInfo); override; + function Load: boolean; override; + function Init: boolean; override; + procedure DeInit; override; + destructor Destroy; override; - //Register Modi Service - Function RegisterModi(nothin: TwParam; pModiInfo: TlParam): integer; //Registers a new Modi. wParam: Pointer to TUS_ModiInfo + //Register modus service + function RegisterModi(nothin: TwParam; pModiInfo: TlParam): integer; //Registers a new modus. wParam: Pointer to TUS_ModiInfo //Start new Party - Function StartParty(NumRounds: TwParam; PAofIRounds: TlParam): integer; //Starts new Party Mode. Returns Non Zero on Success - Function GetCurModi(wParam: TwParam; lParam: TlParam): integer; //Returns Pointer to Cur. Modis TUS_ModiInfo (to Use with Singscreen) - Function StopParty(wParam: TwParam; lParam: TlParam): integer; //Stops Party Mode. Returns 1 If Partymode was enabled before. - Function NextRound(wParam: TwParam; lParam: TlParam): integer; //Increases CurRound by 1; Returns num of Round or -1 if last Round is already played + function StartParty(NumRounds: TwParam; PAofIRounds: TlParam): integer; //Starts new party mode. Returns non zero on success + function GetCurModi(wParam: TwParam; lParam: TlParam): integer; //Returns pointer to cur. Modis TUS_ModiInfo (to Use with Singscreen) + function StopParty(wParam: TwParam; lParam: TlParam): integer; //Stops party mode. Returns 1 if party mode was enabled before. + function NextRound(wParam: TwParam; lParam: TlParam): integer; //Increases curround by 1; Returns num of round or -1 if last round is already played - Function CallModiInit(wParam: TwParam; lParam: TlParam): integer; //Calls CurModis Init Proc. If an Error occurs, Returns Nonzero. In this Case a New Plugin was Selected. Please renew Loading - Function CallModiDeInit(wParam: TwParam; lParam: TlParam): integer; //Calls DeInitProc and does the RoundEnding + function CallModiInit(wParam: TwParam; lParam: TlParam): integer; //Calls curmodis init proc. If an error occurs, returns nonzero. In this case a new plugin was selected. Please renew loading + function CallModiDeInit(wParam: TwParam; lParam: TlParam): integer; //Calls DeInitProc and ends the round - Function GetTeamInfo(wParam: TwParam; pTeamInfo: TlParam): integer; //Writes TTeamInfo Record to Pointer at lParam. Returns Zero on Success - Function SetTeamInfo(wParam: TwParam; pTeamInfo: TlParam): integer; //Read TTeamInfo Record from Pointer at lParam. Returns Zero on Success + function GetTeamInfo(wParam: TwParam; pTeamInfo: TlParam): integer; //Writes TTeamInfo record to pointer at lParam. Returns zero on success + function SetTeamInfo(wParam: TwParam; pTeamInfo: TlParam): integer; //Read TTeamInfo record from pointer at lParam. Returns zero on success - Function GetTeamOrder(wParam: TwParam; lParam: TlParam): integer; //Returns Team Order. Structure: Bits 1..3: Team at Place1; Bits 4..6: Team at Place2 ... - Function GetWinnerString(wParam: TwParam; lParam: TlParam): integer; //wParam is Roundnum. If (Pointer = nil) then Return Length of the String. Otherwise Write the String to Address at lParam + function GetTeamOrder(wParam: TwParam; lParam: TlParam): integer; //Returns team order. Structure: Bits 1..3: Team at place1; Bits 4..6: Team at place2 ... + function GetWinnerString(wParam: TwParam; lParam: TlParam): integer; //wParam is roundnum. If (Pointer = nil) then return length of the string. Otherwise write the string to address at lParam end; const - StandardModi = 0; //Modi ID that will be played in non party Mode + StandardModus = 0; //Modus ID that will be played in non-party mode implementation -uses UCore, UGraphic, UMain, ULanguage, ULog, SysUtils; +uses + UCore, + UGraphic, + ULanguage, + ULog, + UNote, + SysUtils; {********************* TPluginLoader @@ -116,85 +122,84 @@ uses UCore, UGraphic, UMain, ULanguage, ULog, SysUtils; *********************} //------------- -// Function that gives some Infos about the Module to the Core +// function that gives some infos about the module to the core //------------- -Procedure TPartySession.Info(const pInfo: PModuleInfo); +procedure TPartySession.Info(const pInfo: PModuleInfo); begin pInfo^.Name := 'TPartySession'; pInfo^.Version := MakeVersion(1,0,0,chr(0)); - pInfo^.Description := 'Manages Party Modi and Party Game'; + pInfo^.Description := 'Manages party modi and party game'; end; //------------- -// Just the Constructor +// Just the constructor //------------- -Constructor TPartySession.Create; +constructor TPartySession.Create; begin inherited; //UnSet PartyMode - bPartyMode := False; + bPartyMode := false; end; //------------- -//Is Called on Loading. -//In this Method only Events and Services should be created -//to offer them to other Modules or Plugins during the Init process -//If False is Returned this will cause a Forced Exit +//Is called on loading. +//In this method only events and services should be created +//to offer them to other modules or plugins during the init process +//If false is returned this will cause a forced exit //------------- -Function TPartySession.Load: Boolean; +function TPartySession.Load: boolean; begin - //Add Register Party Modi Service - Result := True; + //Add register party modus service + Result := true; Core.Services.AddService('Party/RegisterModi', nil, Self.RegisterModi); Core.Services.AddService('Party/StartParty', nil, Self.StartParty); Core.Services.AddService('Party/GetCurModi', nil, Self.GetCurModi); end; //------------- -//Is Called on Init Process -//In this Method you can Hook some Events and Create + Init -//your Classes, Variables etc. -//If False is Returned this will cause a Forced Exit +//Is called on init process +//In this method you can hook some events and create + init +//your classes, variables etc. +//If false is returned this will cause a forced exit //------------- -Function TPartySession.Init: Boolean; +function TPartySession.Init: boolean; begin - //Just set Prvate Var to true. + //Just set private var to true. Result := true; end; //------------- -//Is Called if this Module has been Inited and there is a Exit. -//Deinit is in backwards Initing Order +//Is called if this module has been inited and there is an exit. +//Deinit is in reverse initing order //------------- -Procedure TPartySession.DeInit; +procedure TPartySession.DeInit; begin //Force DeInit - end; //------------- -//Is Called if this Module will be unloaded and has been created -//Should be used to Free Memory +//Is called if this module will be unloaded and has been created +//Should be used to free memory //------------- -Destructor TPartySession.Destroy; +destructor TPartySession.Destroy; begin - //Just save some Memory if it wasn't done now.. + //Just save some memory if it wasn't done now.. SetLength(Modis, 0); inherited; end; //------------- -// Registers a new Modi. wParam: Pointer to TUS_ModiInfo -// Service for Plugins +// Registers a new modus. wParam: Pointer to TUS_ModiInfo +// Service for plugins //------------- -Function TPartySession.RegisterModi(nothin: TwParam; pModiInfo: TlParam): integer; +function TPartySession.RegisterModi(nothin: TwParam; pModiInfo: TlParam): integer; var - Len: Integer; + Len: integer; Info: PUS_ModiInfo; begin Info := PModiInfo; //Copy Info if cbSize is correct - If (Info.cbSize = SizeOf(TUS_ModiInfo)) then + if (Info.cbSize = SizeOf(TUS_ModiInfo)) then begin Len := Length(Modis); SetLength(Modis, Len + 1); @@ -202,49 +207,49 @@ begin Modis[Len].Info := Info^; end else - Core.ReportError(Integer(PChar('Plugins try to Register Modi with wrong Pointer, or wrong TUS_ModiInfo Record.')), PChar('TPartySession')); + Core.ReportError(integer(PChar('Plugins try to register modus with wrong pointer, or wrong TUS_ModiInfo record.')), PChar('TPartySession')); // FIXME: return a valid result Result := 0; end; //---------- -// Returns a Number of a Random Plugin +// Returns a number of a random plugin //---------- -Function TPartySession.GetRandomPlugin(TeamMode: Boolean): Cardinal; +function TPartySession.GetRandomPlugin(TeamMode: boolean): cardinal; var - LowestTP: Byte; - NumPwithLTP: Word; - I: Integer; - R: Word; + LowestTP: byte; + NumPwithLTP: word; + I: integer; + R: word; begin - Result := StandardModi; //If there are no matching Modis, Play StandardModi - LowestTP := high(Byte); + Result := StandardModus; //If there are no matching modi, play standard modus + LowestTP := high(byte); NumPwithLTP := 0; //Search for Plugins not often played yet - For I := 0 to high(Modis) do + for I := 0 to high(Modis) do begin - if (Modis[I].TimesPlayed < lowestTP) And (((Modis[I].Info.LoadingSettings AND MLS_TeamOnly) <> 0) = TeamMode) then + if (Modis[I].TimesPlayed < lowestTP) and (((Modis[I].Info.LoadingSettings and MLS_TeamOnly) <> 0) = TeamMode) then begin lowestTP := Modis[I].TimesPlayed; NumPwithLTP := 1; end - else if (Modis[I].TimesPlayed = lowestTP) And (((Modis[I].Info.LoadingSettings AND MLS_TeamOnly) <> 0) = TeamMode) then + else if (Modis[I].TimesPlayed = lowestTP) and (((Modis[I].Info.LoadingSettings and MLS_TeamOnly) <> 0) = TeamMode) then begin Inc(NumPwithLTP); end; end; - //Create Random No + //Create random no R := Random(NumPwithLTP); - //Search for Random Plugin - For I := 0 to high(Modis) do + //Search for random plugin + for I := 0 to high(Modis) do begin - if (Modis[I].TimesPlayed = lowestTP) And (((Modis[I].Info.LoadingSettings AND MLS_TeamOnly) <> 0) = TeamMode) then + if (Modis[I].TimesPlayed = lowestTP) and (((Modis[I].Info.LoadingSettings and MLS_TeamOnly) <> 0) = TeamMode) then begin - //Plugin Found + //Plugin found if (R = 0) then begin Result := I; @@ -258,79 +263,79 @@ begin end; //---------- -// Starts new Party Mode. Returns Non Zero on Success +// Starts new party mode. Returns non zero on success //---------- -Function TPartySession.StartParty(NumRounds: TwParam; PAofIRounds: TlParam): integer; +function TPartySession.StartParty(NumRounds: TwParam; PAofIRounds: TlParam): integer; var - I: Integer; + I: integer; aiRounds: PARounds; - TeamMode: Boolean; + TeamMode: boolean; begin Result := 0; - If (Teams.NumTeams >= 1) AND (NumRounds < High(Byte)-1) then + if (Teams.NumTeams >= 1) and (NumRounds < High(byte)-1) then begin bPartyMode := false; aiRounds := PAofIRounds; - Try - //Is this Teammode(More then one Player per Team) ? - TeamMode := True; - For I := 0 to Teams.NumTeams-1 do - TeamMode := TeamMode AND (Teams.Teaminfo[I].NumPlayers > 1); + try + //Is this team mode (More than one player per team) ? + TeamMode := true; + for I := 0 to Teams.NumTeams-1 do + TeamMode := TeamMode and (Teams.Teaminfo[I].NumPlayers > 1); //Set Rounds SetLength(Rounds, NumRounds); - For I := 0 to High(Rounds) do - begin //Set Plugins - If (aiRounds[I] = -1) then + for I := 0 to High(Rounds) do + begin //Set plugins + if (aiRounds[I] = -1) then Rounds[I].Modi := GetRandomPlugin(TeamMode) - Else If (aiRounds[I] >= 0) AND (aiRounds[I] <= High(Modis)) AND (TeamMode OR ((Modis[aiRounds[I]].Info.LoadingSettings AND MLS_TeamOnly) = 0)) then + else if (aiRounds[I] >= 0) and (aiRounds[I] <= High(Modis)) and (TeamMode or ((Modis[aiRounds[I]].Info.LoadingSettings and MLS_TeamOnly) = 0)) then Rounds[I].Modi := aiRounds[I] - Else - Rounds[I].Modi := StandardModi; + else + Rounds[I].Modi := StandardModus; - Rounds[I].Winner := High(Byte); //Set Winner to Not Played + Rounds[I].Winner := High(byte); //Set winner to not played end; - CurRound := High(Byte); //Set CurRound to not defined + CurRound := High(byte); //Set CurRound to not defined - //Return teh true and Set PartyMode - bPartyMode := True; + //Return true and set party mode + bPartyMode := true; Result := 1; - Except - Core.ReportError(Integer(PChar('Can''t start PartyMode.')), PChar('TPartySession')); + except + Core.ReportError(integer(PChar('Can''t start party mode.')), PChar('TPartySession')); end; end; end; //---------- -// Returns Pointer to Cur. ModiInfoEx (to Use with Singscreen) +// Returns pointer to Cur. ModiInfoEx (to use with sing screen) //---------- -Function TPartySession.GetCurModi(wParam: TwParam; lParam: TlParam): integer; +function TPartySession.GetCurModi(wParam: TwParam; lParam: TlParam): integer; begin - If (bPartyMode) AND (CurRound <= High(Rounds)) then + if (bPartyMode) and (CurRound <= High(Rounds)) then begin //If PartyMode is enabled: //Return the Plugin of the Cur Round - Result := Integer(@Modis[Rounds[CurRound].Modi]); + Result := integer(@Modis[Rounds[CurRound].Modi]); end else - begin //Return StandardModi - Result := Integer(@Modis[StandardModi]); + begin //Return standard modus + Result := integer(@Modis[StandardModus]); end; end; //---------- -// Stops Party Mode. Returns 1 If Partymode was enabled before. And -1 if Change was not possible +// Stops party mode. Returns 1 if party mode was enabled before and -1 if change was not possible //---------- -Function TPartySession.StopParty(wParam: TwParam; lParam: TlParam): integer; +function TPartySession.StopParty(wParam: TwParam; lParam: TlParam): integer; begin Result := -1; - If (bPartyMode) then + if (bPartyMode) then begin - // to-do : Whitü: Check here if SingScreen is not Shown atm. - bPartyMode := False; + // to-do : Whitü: Check here if sing screen is not shown atm. + bPartyMode := false; Result := 1; end else @@ -338,59 +343,60 @@ begin end; //---------- -//GetRandomPlayer - Gives back a Random Player to Play next Round +//GetRandomPlayer - gives back a random player to play next round //---------- -function TPartySession.GetRandomPlayer(Team: Byte): Byte; +function TPartySession.GetRandomPlayer(Team: byte): byte; var - I, R: Integer; - lowestTP: Byte; - NumPwithLTP: Byte; + I, R: integer; + lowestTP: byte; + NumPwithLTP: byte; begin - LowestTP := high(Byte); - NumPwithLTP := 0; - Result := 0; + LowestTP := high(byte); + NumPwithLTP := 0; + Result := 0; - //Search for Players that have not often played yet - For I := 0 to Teams.Teaminfo[Team].NumPlayers-1 do + //Search for players that have not often played yet + for I := 0 to Teams.Teaminfo[Team].NumPlayers-1 do + begin + if (Teams.Teaminfo[Team].Playerinfo[I].TimesPlayed < lowestTP) then begin - if (Teams.Teaminfo[Team].Playerinfo[I].TimesPlayed < lowestTP) then - begin - lowestTP := Teams.Teaminfo[Team].Playerinfo[I].TimesPlayed; - NumPwithLTP := 1; - end - else if (Teams.Teaminfo[Team].Playerinfo[I].TimesPlayed = lowestTP) then - begin - Inc(NumPwithLTP); - end; + lowestTP := Teams.Teaminfo[Team].Playerinfo[I].TimesPlayed; + NumPwithLTP := 1; + end + else if (Teams.Teaminfo[Team].Playerinfo[I].TimesPlayed = lowestTP) then + begin + Inc(NumPwithLTP); end; + end; - //Create Random No - R := Random(NumPwithLTP); + //Create random no + R := Random(NumPwithLTP); - //Search for Random Player - For I := 0 to Teams.Teaminfo[Team].NumPlayers-1 do + //Search for random player + for I := 0 to Teams.Teaminfo[Team].NumPlayers-1 do + begin + if Teams.Teaminfo[Team].Playerinfo[I].TimesPlayed = lowestTP then begin - if Teams.Teaminfo[Team].Playerinfo[I].TimesPlayed = lowestTP then + //Player found + if (R = 0) then begin - //Player Found - if (R = 0) then - begin - Result := I; - Break; - end; - - Dec(R); + Result := I; + Break; end; + + Dec(R); end; + end; end; //---------- -// NextRound - Increases CurRound by 1; Returns num of Round or -1 if last Round is already played +// NextRound - Increases CurRound by 1; Returns num of round or -1 if last round is already played //---------- -Function TPartySession.NextRound(wParam: TwParam; lParam: TlParam): integer; -var I: Integer; +function TPartySession.NextRound(wParam: TwParam; lParam: TlParam): integer; +var + I: integer; begin - If ((CurRound < high(Rounds)) OR (CurRound = high(CurRound))) then + if ((CurRound < high(Rounds)) or (CurRound = high(CurRound))) then begin //everythings OK! -> Start the Round, maaaaan Inc(CurRound); @@ -406,23 +412,23 @@ begin end; //---------- -//IsWinner - Returns True if the Players Bit is set in the Winner Byte +//IsWinner - returns true if the players bit is set in the winner byte //---------- -function TPartySession.IsWinner(Player, Winner: Byte): boolean; +function TPartySession.IsWinner(Player, Winner: byte): boolean; var - Bit: Byte; + Bit: byte; begin Bit := 1 shl Player; - Result := ((Winner AND Bit) = Bit); + Result := ((Winner and Bit) = Bit); end; //---------- -//GenScores - Inc Scores for Cur. Round +//GenScores - inc scores for cur. round //---------- procedure TPartySession.GenScores; var - I: Byte; + I: byte; begin for I := 0 to Teams.NumTeams-1 do begin @@ -432,86 +438,86 @@ begin end; //---------- -// CallModiInit - Calls CurModis Init Proc. If an Error occurs, Returns Nonzero. In this Case a New Plugin was Selected. Please renew Loading +// CallModiInit - calls CurModis Init Proc. If an error occurs, returns nonzero. In this case a new plugin was selected. Please renew loading //---------- -Function TPartySession.CallModiInit(wParam: TwParam; lParam: TlParam): integer; +function TPartySession.CallModiInit(wParam: TwParam; lParam: TlParam): integer; begin - If (not bPartyMode) then - begin //Set Rounds if not in PartyMode + if (not bPartyMode) then + begin //Set rounds if not in party mode SetLength(Rounds, 1); - Rounds[0].Modi := StandardModi; - Rounds[0].Winner := High(Byte); + Rounds[0].Modi := StandardModus; + Rounds[0].Winner := High(byte); CurRound := 0; end; - Try + try //Core. - Except + except on E : Exception do begin - Core.ReportError(Integer(PChar('Error starting Modi: ' + Modis[Rounds[CurRound].Modi].Info.Name + ' ErrorStr: ' + E.Message)), PChar('TPartySession')); - If (Rounds[CurRound].Modi = StandardModi) then + Core.ReportError(integer(PChar('Error starting modus: ' + Modis[Rounds[CurRound].Modi].Info.Name + ' ErrorStr: ' + E.Message)), PChar('TPartySession')); + if (Rounds[CurRound].Modi = StandardModus) then begin - Core.ReportError(Integer(PChar('Can''t start StandardModi, will exit now!')), PChar('TPartySession')); + Core.ReportError(integer(PChar('Can''t start standard modus, will exit now!')), PChar('TPartySession')); Halt; end - Else //Select StandardModi + else //Select standard modus begin - Rounds[CurRound].Modi := StandardModi + Rounds[CurRound].Modi := StandardModus end; end; - End; + end; // FIXME: return a valid result Result := 0; end; //---------- -// CallModiDeInit - Calls DeInitProc and does the RoundEnding +// CallModiDeInit - calls DeInitProc and ends the round //---------- -Function TPartySession.CallModiDeInit(wParam: TwParam; lParam: TlParam): integer; +function TPartySession.CallModiDeInit(wParam: TwParam; lParam: TlParam): integer; var - I: Integer; - MaxScore: Word; + I: integer; + MaxScore: word; begin - If (bPartyMode) then + if (bPartyMode) then begin //Get Winner Byte! - if (@Modis[Rounds[CurRound].Modi].Info.ModiDeInit <> nil) then //get Winners from Plugin + if (@Modis[Rounds[CurRound].Modi].Info.ModiDeInit <> nil) then //get winners from plugin Rounds[CurRound].Winner := Modis[Rounds[CurRound].Modi].Info.ModiDeInit(Modis[Rounds[CurRound].Modi].Info.ID) else - begin //Create winners by Score :/ + begin //Create winners by score :/ Rounds[CurRound].Winner := 0; MaxScore := 0; for I := 0 to Teams.NumTeams-1 do begin - // to-do : recode Percentage stuff + // to-do : recode percentage stuff //PlayerInfo.Playerinfo[I].Percentage := PlayerInfo.Playerinfo[I].Score div 9999; if (Player[I].ScoreTotalInt > MaxScore) then begin MaxScore := Player[I].ScoreTotalInt; Rounds[CurRound].Winner := 1 shl I; end - else if (Player[I].ScoreTotalInt = MaxScore) AND (Player[I].ScoreTotalInt <> 0) then + else if (Player[I].ScoreTotalInt = MaxScore) and (Player[I].ScoreTotalInt <> 0) then begin Rounds[CurRound].Winner := Rounds[CurRound].Winner or (1 shl I); end; end; - //When nobody has Points -> Everybody loose + //When nobody has points -> everybody looses if (MaxScore = 0) then Rounds[CurRound].Winner := 0; end; - //Generate teh Scores + //Generate the scores GenScores; - //Inc Players TimesPlayed - If ((Modis[Rounds[CurRound-1].Modi].Info.LoadingSettings AND MLS_IncTP) = MLS_IncTP) then + //Inc players TimesPlayed + if ((Modis[Rounds[CurRound-1].Modi].Info.LoadingSettings and MLS_IncTP) = MLS_IncTP) then begin - For I := 0 to Teams.NumTeams-1 do + for I := 0 to Teams.NumTeams-1 do Inc(Teams.TeamInfo[I].Playerinfo[Teams.TeamInfo[I].CurPlayer].TimesPlayed); end; end @@ -523,69 +529,70 @@ begin end; //---------- -// GetTeamInfo - Writes TTeamInfo Record to Pointer at lParam. Returns Zero on Success +// GetTeamInfo - writes TTeamInfo record to pointer at lParam. Returns zero on success //---------- -Function TPartySession.GetTeamInfo(wParam: TwParam; pTeamInfo: TlParam): integer; -var Info: ^TTeamInfo; +function TPartySession.GetTeamInfo(wParam: TwParam; pTeamInfo: TlParam): integer; +var + Info: ^TTeamInfo; begin Result := -1; Info := pTeamInfo; - If (Info <> nil) then + if (Info <> nil) then begin - Try + try // to - do : Check Delphi memory management in this case //Not sure if i had to copy PChars to a new address or if delphi manages this o0 Info^ := Teams; Result := 0; - Except + except Result := -2; - End; + end; end; end; //---------- -// SetTeamInfo - Read TTeamInfo Record from Pointer at lParam. Returns Zero on Success +// SetTeamInfo - read TTeamInfo record from pointer at lParam. Returns zero on success //---------- -Function TPartySession.SetTeamInfo(wParam: TwParam; pTeamInfo: TlParam): integer; +function TPartySession.SetTeamInfo(wParam: TwParam; pTeamInfo: TlParam): integer; var TeamInfobackup: TTeamInfo; Info: ^TTeamInfo; begin Result := -1; Info := pTeamInfo; - If (Info <> nil) then + if (Info <> nil) then begin - Try + try TeamInfoBackup := Teams; // to - do : Check Delphi memory management in this case //Not sure if i had to copy PChars to a new address or if delphi manages this o0 Teams := Info^; Result := 0; - Except + except Teams := TeamInfoBackup; Result := -2; - End; + end; end; end; //---------- -// GetTeamOrder - Returns Team Order. Structure: Bits 1..3: Team at Place1; Bits 4..6: Team at Place2 ... +// GetTeamOrder - returns team order. Structure: Bits 1..3: Team at place1; Bits 4..6: Team at place2 ... //---------- -Function TPartySession.GetTeamOrder(wParam: TwParam; lParam: TlParam): integer; +function TPartySession.GetTeamOrder(wParam: TwParam; lParam: TlParam): integer; var - I, J: Integer; + I, J: integer; ATeams: array [0..5] of TeamOrderEntry; TempTeam: TeamOrderEntry; begin - // to-do : PartyMode: Write this in another way, so that teams with the same scire get the same Placing - //Fill Team Array - For I := 0 to Teams.NumTeams-1 do + // to-do : PartyMode: Write this in another way, so that teams with the same score get the same place + //Fill Team array + for I := 0 to Teams.NumTeams-1 do begin ATeams[I].Teamnum := I; ATeams[I].Score := Teams.Teaminfo[I].Score; end; - //Sort Teams + //Sort teams for J := 0 to Teams.NumTeams-1 do for I := 1 to Teams.NumTeams-1 do if ATeams[I].Score > ATeams[I-1].Score then @@ -597,17 +604,17 @@ begin //Copy to Result Result := 0; - For I := 0 to Teams.NumTeams-1 do + for I := 0 to Teams.NumTeams-1 do Result := Result or (ATeams[I].TeamNum Shl I*3); end; //---------- -// GetWinnerString - wParam is Roundnum. If (Pointer = nil) then Return Length of the String. Otherwise Write the String to Address at lParam +// GetWinnerString - wParam is Roundnum. If (pointer = nil) then return length of the string. Otherwise write the string to address at lParam //---------- -Function TPartySession.GetWinnerString(wParam: TwParam; lParam: TlParam): integer; +function TPartySession.GetWinnerString(wParam: TwParam; lParam: TlParam): integer; var Winners: array of UTF8String; - I: Integer; + I: integer; ResultStr: String; S: ^String; begin @@ -637,21 +644,21 @@ begin end; end; - //Now Return what we have got - If (lParam = nil) then - begin //ReturnString Length + //Now return what we have got + if (lParam = nil) then + begin //Return string length Result := Length(ResultStr); end - Else - begin //Return String - Try + else + begin //Return string + try S := lParam; S^ := ResultStr; Result := 0; - Except + except Result := -1; - End; + end; end; end; diff --git a/unicode/src/base/UPath.pas b/unicode/src/base/UPath.pas new file mode 100644 index 00000000..2316ac02 --- /dev/null +++ b/unicode/src/base/UPath.pas @@ -0,0 +1,188 @@ +{* UltraStar Deluxe - Karaoke Game + * + * UltraStar Deluxe is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + * + * $URL: https://ultrastardx.svn.sourceforge.net/svnroot/ultrastardx/trunk/src/base/UPath.pas $ + * $Id: UPath.pas 1624 2009-03-06 23:45:10Z k-m_schindler $ + *} + +unit UPath; + +interface + +{$IFDEF FPC} + {$MODE Delphi} +{$ENDIF} + +{$I switches.inc} + +uses + SysUtils, + Classes; + +var + // Absolute Paths + GamePath: string; + SoundPath: string; + SongPaths: TStringList; + LogPath: string; + ThemePath: string; + SkinsPath: string; + ScreenshotsPath: string; + CoverPaths: TStringList; + LanguagesPath: string; + PluginPath: string; + VisualsPath: string; + FontPath: string; + ResourcesPath: string; + PlayListPath: string; + +function FindPath(out PathResult: string; const RequestedPath: string; NeedsWritePermission: boolean): boolean; +procedure InitializePaths; +procedure AddSongPath(const Path: string); + +implementation + +uses + StrUtils, + UPlatform, + UCommandLine, + ULog; + +procedure AddSpecialPath(var PathList: TStringList; const Path: string); +var + Index: integer; + PathAbs, OldPathAbs: string; +begin + if (PathList = nil) then + PathList := TStringList.Create; + + if (Path = '') or not ForceDirectories(Path) then + Exit; + + PathAbs := IncludeTrailingPathDelimiter(ExpandFileName(Path)); + + // check if path or a part of the path was already added + for Index := 0 to PathList.Count-1 do + begin + OldPathAbs := IncludeTrailingPathDelimiter(ExpandFileName(PathList[Index])); + // check if the new directory is a sub-directory of a previously added one. + // This is also true, if both paths point to the same directories. + if (AnsiStartsText(OldPathAbs, PathAbs)) then + begin + // ignore the new path + Exit; + end; + + // check if a previously added directory is a sub-directory of the new one. + if (AnsiStartsText(PathAbs, OldPathAbs)) then + begin + // replace the old with the new one. + PathList[Index] := PathAbs; + Exit; + end; + end; + + PathList.Add(PathAbs); +end; + +procedure AddSongPath(const Path: string); +begin + AddSpecialPath(SongPaths, Path); +end; + +procedure AddCoverPath(const Path: string); +begin + AddSpecialPath(CoverPaths, Path); +end; + +(** + * Initialize a path variable + * After setting paths, make sure that paths exist + *) +function FindPath(out PathResult: string; + const RequestedPath: string; + NeedsWritePermission: boolean) + : boolean; +begin + Result := false; + + if (RequestedPath = '') then + Exit; + + // Make sure the directory exists + if (not ForceDirectories(RequestedPath)) then + begin + PathResult := ''; + Exit; + end; + + PathResult := IncludeTrailingPathDelimiter(RequestedPath); + + if (NeedsWritePermission) and + (FileIsReadOnly(RequestedPath)) then + begin + Exit; + end; + + Result := true; +end; + +(** + * Function sets all absolute paths e.g. song path and makes sure the directorys exist + *) +procedure InitializePaths; +begin + // Log directory (must be writable) + if (not FindPath(LogPath, Platform.GetLogPath, true)) then + begin + Log.FileOutputEnabled := false; + Log.LogWarn('Log directory "'+ Platform.GetLogPath +'" not available', 'InitializePaths'); + end; + + FindPath(SoundPath, Platform.GetGameSharedPath + 'sounds', false); + FindPath(ThemePath, Platform.GetGameSharedPath + 'themes', false); + FindPath(SkinsPath, Platform.GetGameSharedPath + 'themes', false); + FindPath(LanguagesPath, Platform.GetGameSharedPath + 'languages', false); + FindPath(PluginPath, Platform.GetGameSharedPath + 'plugins', false); + FindPath(VisualsPath, Platform.GetGameSharedPath + 'visuals', false); + FindPath(FontPath, Platform.GetGameSharedPath + 'fonts', false); + FindPath(ResourcesPath, Platform.GetGameSharedPath + 'resources', false); + + // Playlists are not shared as we need one directory to write too + FindPath(PlaylistPath, Platform.GetGameUserPath + 'playlists', true); + + // Screenshot directory (must be writable) + if (not FindPath(ScreenshotsPath, Platform.GetGameUserPath + 'screenshots', true)) then + begin + Log.LogWarn('Screenshot directory "'+ Platform.GetGameUserPath +'" not available', 'InitializePaths'); + end; + + // Add song paths + AddSongPath(Params.SongPath); + AddSongPath(Platform.GetGameSharedPath + 'songs'); + AddSongPath(Platform.GetGameUserPath + 'songs'); + + // Add category cover paths + AddCoverPath(Platform.GetGameSharedPath + 'covers'); + AddCoverPath(Platform.GetGameUserPath + 'covers'); +end; + +end. diff --git a/unicode/src/base/UPlatformMacOSX.pas b/unicode/src/base/UPlatformMacOSX.pas index 1aa37cd4..96e4bc63 100644 --- a/unicode/src/base/UPlatformMacOSX.pas +++ b/unicode/src/base/UPlatformMacOSX.pas @@ -47,19 +47,21 @@ type * (Note for non-Maccies: "folder" is the Mac name for directory.) * * Note on the resource folders: - * 1. Installation of an application on the mac works as follows: Extract and copy an application - * and if you don't like or need the application anymore you move the folder - * to the trash - and you're done. - * 2. The use folders in the user's home directory is against Apple's guidelines - * and strange to an average user. + * 1. Installation of an application on the mac works as follows: Extract and + * copy an application and if you don't like or need the application + * anymore you move the folder to the trash - and you're done. + * 2. The use of folders in the user's home directory is against Apple's + * guidelines and strange to an average user. * 3. Even worse is using /usr/local/... since all lowercase folders in / are - * not visible to an average user in the Finder, at least not without some "tricks". + * not visible to an average user in the Finder, at least not without some + * "tricks". * - * The best way would be to store everything within the application bundle. However, this - * requires USDX to offer the handling of the resources. Until this is implemented, the - * second best solution is as follows: + * The best way would be to store everything within the application bundle. + * However, this requires USDX to offer the handling of the resources. Until + * this is implemented, the second best solution is as follows: * - * According to Aple guidelines handling of resources and folders should follow these lines: + * According to Aple guidelines handling of resources and folders should follow + * these lines: * * Acceptable places for files are folders named UltraStarDeluxe either in * /Library/Application Support/ @@ -68,19 +70,19 @@ type * * So * GetGameSharedPath could return - * /Library/Application Support/UltraStarDeluxe/Resources/. + * /Library/Application Support/UltraStarDeluxe/. * GetGameUserPath could return - * ~/Library/Application Support/UltraStarDeluxe/Resources/. + * ~/Library/Application Support/UltraStarDeluxe/. * - * Right now, only $HOME/Library/Application Support/UltraStarDeluxe/Resources + * Right now, only $HOME/Library/Application Support/UltraStarDeluxe * is used. So every user needs the complete set of files and folders. * Future versions may also use shared resources in - * /Library/Application Support/UltraStarDeluxe/Resources. However, this is not - * treated yet in the code outside this unit. + * /Library/Application Support/UltraStarDeluxe. However, this is + * not treated yet in the code outside this unit. * * USDX checks, whether GetGameUserPath exists. If not, USDX creates it. * The existence of needed files is then checked and if a file is missing - * it is copied to there from within the Resources folder in the Application + * it is copied to there from within the folder Contents in the Application * bundle, which contains the default files. USDX should not delete files or * folders in Application Support/UltraStarDeluxe automatically or without * user confirmation. @@ -88,13 +90,14 @@ type TPlatformMacOSX = class(TPlatform) private {** - * GetBundlePath returns the path to the application bundle UltraStarDeluxe.app. + * GetBundlePath returns the path to the application bundle + * UltraStarDeluxe.app. *} function GetBundlePath: WideString; {** * GetApplicationSupportPath returns the path to - * $HOME/Library/Application Support/UltraStarDeluxe/Resources. + * $HOME/Library/Application Support/UltraStarDeluxe. *} function GetApplicationSupportPath: WideString; @@ -102,38 +105,38 @@ type * see the description of @link(Init). *} procedure CreateUserFolders(); - + public {** - * Init simply calls @link(CreateUserFolders), which in turn scans the folder - * UltraStarDeluxe.app/Contents/Resources for all files and folders. - * $HOME/Library/Application Support/UltraStarDeluxe/Resources is then checked - * for their presence and missing ones are copied. + * Init simply calls @link(CreateUserFolders), which in turn scans the + * folder UltraStarDeluxe.app/Contents for all files and + * folders. $HOME/Library/Application Support/UltraStarDeluxe + * is then checked for their presence and missing ones are copied. *} procedure Init; override; {** - * DirectoryFindFiles returns all entries of a folder with names and booleans - * about their type, i.e. file or directory. + * DirectoryFindFiles returns all entries of a folder with names and + * booleans about their type, i.e. file or directory. *} function DirectoryFindFiles(Dir, Filter: WideString; ReturnAllSubDirs: boolean): TDirectoryEntryArray; override; {** * GetLogPath returns the path for log messages. Currently it is set to - * $HOME/Library/Application Support/UltraStarDeluxe/Resources/Log. + * $HOME/Library/Application Support/UltraStarDeluxe/Log. *} function GetLogPath : WideString; override; {** - * GetGameSharedPath returns the path for shared resources. Currently it is set to - * /Library/Application Support/UltraStarDeluxe/Resources. + * GetGameSharedPath returns the path for shared resources. Currently it + * is set to /Library/Application Support/UltraStarDeluxe. * However it is not used. *} function GetGameSharedPath : WideString; override; {** - * GetGameUserPath returns the path for user resources. Currently it is set to - * $HOME/Library/Application Support/UltraStarDeluxe/Resources. + * GetGameUserPath returns the path for user resources. Currently it is + * set to $HOME/Library/Application Support/UltraStarDeluxe. * This is where a user can add songs, themes, .... *} function GetGameUserPath : WideString; override; @@ -151,6 +154,9 @@ begin end; procedure TPlatformMacOSX.CreateUserFolders(); +const + // used to construct the @link(UserPathName) + PathName: string = '/Library/Application Support/UltraStarDeluxe'; var RelativePath: string; // BaseDir contains the path to the folder, where a search is performed. @@ -169,22 +175,23 @@ var // searched for additional files and folders. DirectoryIsFinished: longint; Counter: longint; + // These three are for creating directories, due to possible symlinks + CreatedDirectory: boolean; + FileAttrs: integer; + DirectoryPath: string; - UserPathName: string; -const - // used to construct the @link(UserPathName) - PathName: string = '/Library/Application Support/UltraStarDeluxe/Resources'; + UserPathName: string; begin // Get the current folder and save it in OldBaseDir for returning to it, when // finished. GetDir(0, OldBaseDir); - // UltraStarDeluxe.app/Contents/Resources contains all the default files and + // UltraStarDeluxe.app/Contents contains all the default files and // folders. - BaseDir := OldBaseDir + '/UltraStarDeluxe.app/Contents/Resources'; + BaseDir := OldBaseDir + '/UltraStarDeluxe.app/Contents'; ChDir(BaseDir); - // Right now, only $HOME/Library/Application Support/UltraStarDeluxe/Resources + // Right now, only $HOME/Library/Application Support/UltraStarDeluxe // is used. UserPathName := GetEnvironmentVariable('HOME') + PathName; @@ -192,7 +199,7 @@ begin DirectoryList := TStringList.Create(); FileList := TStringList.Create(); DirectoryList.Add('.'); - + // create the folder and file lists repeat @@ -203,7 +210,7 @@ begin repeat if DirectoryExists(SearchInfo.Name) then begin - if (SearchInfo.Name <> '.') and (SearchInfo.Name <> '..') then + if (SearchInfo.Name <> '.') and (SearchInfo.Name <> '..') then DirectoryList.Add(RelativePath + '/' + SearchInfo.Name); end else @@ -218,7 +225,12 @@ begin ForceDirectories(UserPathName); // should not be necessary since (UserPathName+'/.') is created. for Counter := 0 to DirectoryList.Count-1 do begin - if not ForceDirectories(UserPathName + '/' + DirectoryList[Counter]) then + DirectoryPath := UserPathName + '/' + DirectoryList[Counter]; + CreatedDirectory := ForceDirectories(DirectoryPath); + FileAttrs := FileGetAttr(DirectoryPath); + // Don't know how to analyse the target of the link. + // Let's assume the symlink is pointing to an existing directory. + if (not CreatedDirectory) and (FileAttrs and faSymLink > 0) then Log.LogError('Failed to create the folder "'+ UserPathName + '/' + DirectoryList[Counter] +'"', 'TPlatformMacOSX.CreateUserFolders'); end; @@ -241,8 +253,7 @@ var i, pos : integer; begin // Mac applications are packaged in folders. - // We have to cut the last two folders - // to get the application folder. + // Cutting the last two folders yields the application folder. Result := GetExecutionDir(); for i := 1 to 2 do @@ -257,7 +268,7 @@ end; function TPlatformMacOSX.GetApplicationSupportPath: WideString; const - PathName : string = '/Library/Application Support/UltraStarDeluxe/Resources'; + PathName : string = '/Library/Application Support/UltraStarDeluxe'; begin Result := GetEnvironmentVariable('HOME') + PathName + '/'; end; @@ -287,7 +298,7 @@ begin i := 0; Filter := LowerCase(Filter); - TheDir := FPOpenDir(Dir); + TheDir := FPOpenDir(Dir); if Assigned(TheDir) then repeat ADirent := FPReadDir(TheDir); diff --git a/unicode/src/base/UPlaylist.pas b/unicode/src/base/UPlaylist.pas index 47ade154..744f4ce8 100644 --- a/unicode/src/base/UPlaylist.pas +++ b/unicode/src/base/UPlaylist.pas @@ -34,7 +34,8 @@ interface {$I switches.inc} uses - USong; + USong, + UPath; type TPlaylistItem = record diff --git a/unicode/src/base/UPluginLoader.pas b/unicode/src/base/UPluginLoader.pas index 5e581c23..8836cb78 100644 --- a/unicode/src/base/UPluginLoader.pas +++ b/unicode/src/base/UPluginLoader.pas @@ -41,14 +41,15 @@ interface uses UPluginDefs, - UCoreModule; + UCoreModule, + UPath; type TPluginListItem = record Info: TUS_PluginInfo; - State: Byte; // State of this plugin: 0 - undefined; 1 - loaded; 2 - inited / running; 4 - unloaded; 254 - loading aborted by plugin; 255 - unloaded because of error - Path: String; // path to this plugin - NeedsDeInit: Boolean; // if this is inited correctly this should be true + State: byte; // State of this plugin: 0 - undefined; 1 - loaded; 2 - inited / running; 4 - unloaded; 254 - loading aborted by plugin; 255 - unloaded because of error + Path: string; // path to this plugin + NeedsDeInit: boolean; // if this is inited correctly this should be true hLib: THandle; // handle of loaded libary Procs: record // procs offered by plugin. Don't call this directly use wrappers of TPluginLoader Load: Func_Load; @@ -63,13 +64,13 @@ type PPluginLoader = ^TPluginLoader; TPluginLoader = class (TCoreModule) private - LoadingProcessFinished: Boolean; + LoadingProcessFinished: boolean; sUnloadPlugin: THandle; sLoadPlugin: THandle; sGetPluginInfo: THandle; sGetPluginState: THandle; - procedure FreePlugin(Index: Cardinal); + procedure FreePlugin(Index: integer); public PluginInterface: TUS_PluginInterface; Plugins: array of TPluginListItem; @@ -77,19 +78,19 @@ type // TCoreModule methods to inherit constructor Create; override; procedure Info(const pInfo: PModuleInfo); override; - function Load: Boolean; override; - function Init: Boolean; override; + function Load: boolean; override; + function Init: boolean; override; procedure DeInit; override; Destructor Destroy; override; // New methods - procedure BrowseDir(Path: String); // browses the path at _Path_ for plugins - function PluginExists(Name: String): integer; // if plugin exists: Index of plugin, else -1 - procedure AddPlugin(Filename: String); // adds plugin to the array + procedure BrowseDir(Path: string); // browses the path at _Path_ for plugins + function PluginExists(Name: string): integer; // if plugin exists: Index of plugin, else -1 + procedure AddPlugin(Filename: string); // adds plugin to the array - function CallLoad(Index: Cardinal): integer; - function CallInit(Index: Cardinal): integer; - procedure CallDeInit(Index: Cardinal); + function CallLoad(Index: integer): integer; + function CallInit(Index: integer): integer; + procedure CallDeInit(Index: integer); //Services offered function LoadPlugin(wParam: TwParam; lParam: TlParam): integer; //wParam PChar(PluginName/PluginPath) | lParam (if wParam = nil) ID of the Plugin @@ -110,10 +111,10 @@ type public // TCoreModule methods to inherit constructor Create; override; - + procedure Info(const pInfo: PModuleInfo); override; - function Load: Boolean; override; - function Init: Boolean; override; + function Load: boolean; override; + function Init: boolean; override; procedure DeInit; override; end; @@ -176,7 +177,7 @@ begin PluginInterface.ServiceExists := ServiceExists; // UnSet private var - LoadingProcessFinished := False; + LoadingProcessFinished := false; end; //------------- @@ -185,15 +186,15 @@ end; // to offer them to other modules or plugins during the init process // if false is returned this will cause a forced exit //------------- -function TPluginLoader.Load: Boolean; +function TPluginLoader.Load: boolean; begin - Result := True; + Result := true; try // Start searching for plugins BrowseDir(PluginPath); except - Result := False; + Result := false; Core.ReportError(integer(PChar('Error browsing and loading.')), PChar('TPluginLoader')); end; end; @@ -204,11 +205,11 @@ end; // your classes, variables etc. // If false is returned this will cause a forced exit //------------- -function TPluginLoader.Init: Boolean; +function TPluginLoader.Init: boolean; begin // Just set private var to true. - LoadingProcessFinished := True; - Result := True; + LoadingProcessFinished := true; + Result := true; end; //------------- @@ -244,7 +245,7 @@ end; //-------------- // Browses the path at _Path_ for plugins //-------------- -procedure TPluginLoader.BrowseDir(Path: String); +procedure TPluginLoader.BrowseDir(Path: string); var SR: TSearchRec; begin @@ -256,7 +257,7 @@ begin until FindNext(SR) <> 0; end; FindClose(SR); - + // Search for plugins at path if FindFirst(Path + '*' + PluginFileExtension, 0, SR) = 0 then begin @@ -266,11 +267,11 @@ begin end; FindClose(SR); end; - + //-------------- // If plugin exists: Index of plugin, else -1 //-------------- -function TPluginLoader.PluginExists(Name: String): integer; +function TPluginLoader.PluginExists(Name: string): integer; var I: integer; begin @@ -286,11 +287,11 @@ begin end; end; end; - + //-------------- // Adds plugin to the array //-------------- -procedure TPluginLoader.AddPlugin(Filename: String); +procedure TPluginLoader.AddPlugin(Filename: string); var hLib: THandle; PInfo: Proc_PluginInfo; @@ -332,7 +333,7 @@ begin Plugins[PluginID].Info := Info; Plugins[PluginID].State := 0; Plugins[PluginID].Path := Filename; - Plugins[PluginID].NeedsDeInit := False; + Plugins[PluginID].NeedsDeInit := false; Plugins[PluginID].hLib := hLib; // Try to get procs @@ -340,7 +341,7 @@ begin Plugins[PluginID].Procs.Init := GetProcAddress (hLib, PChar('USPlugin_Init')); Plugins[PluginID].Procs.DeInit := GetProcAddress (hLib, PChar('USPlugin_DeInit')); - if (@Plugins[PluginID].Procs.Load = nil) OR (@Plugins[PluginID].Procs.Init = nil) OR (@Plugins[PluginID].Procs.DeInit = nil) then + if (@Plugins[PluginID].Procs.Load = nil) or (@Plugins[PluginID].Procs.Init = nil) or (@Plugins[PluginID].Procs.DeInit = nil) then begin Plugins[PluginID].State := 255; FreeLibrary(hLib); @@ -354,11 +355,11 @@ begin CallInit(PluginID); end; end - else if (LoadingProcessFinished = False) then + else if (LoadingProcessFinished = false) then begin if (Plugins[PluginID].Info.Version < Info.Version) then begin // Found newer version of this plugin - Core.ReportDebug(integer(PChar('Found a newer version of plugin: ' + String(Info.Name))), PChar('TPluginLoader')); + Core.ReportDebug(integer(PChar('Found a newer version of plugin: ' + string(Info.Name))), PChar('TPluginLoader')); // Unload old plugin UnloadPlugin(PluginID, nil); @@ -367,7 +368,7 @@ begin Plugins[PluginID].Info := Info; Plugins[PluginID].State := 0; Plugins[PluginID].Path := Filename; - Plugins[PluginID].NeedsDeInit := False; + Plugins[PluginID].NeedsDeInit := false; Plugins[PluginID].hLib := hLib; // Try to get procs @@ -375,7 +376,7 @@ begin Plugins[PluginID].Procs.Init := GetProcAddress (hLib, PChar('USPlugin_Init')); Plugins[PluginID].Procs.DeInit := GetProcAddress (hLib, PChar('USPlugin_DeInit')); - if (@Plugins[PluginID].Procs.Load = nil) OR (@Plugins[PluginID].Procs.Init = nil) OR (@Plugins[PluginID].Procs.DeInit = nil) then + if (@Plugins[PluginID].Procs.Load = nil) or (@Plugins[PluginID].Procs.Init = nil) or (@Plugins[PluginID].Procs.DeInit = nil) then begin FreeLibrary(hLib); Plugins[PluginID].State := 255; @@ -390,7 +391,7 @@ begin else begin FreeLibrary(hLib); - Core.ReportError(integer(PChar('Plugin with this name already exists: ' + String(Info.Name))), PChar('TPluginLoader')); + Core.ReportError(integer(PChar('Plugin with this name already exists: ' + string(Info.Name))), PChar('TPluginLoader')); end; end else @@ -413,7 +414,7 @@ end; //-------------- // Calls load func of plugin with the given index //-------------- -function TPluginLoader.CallLoad(Index: Cardinal): integer; +function TPluginLoader.CallLoad(Index: integer): integer; begin Result := -2; if(Index < Length(Plugins)) then @@ -424,7 +425,7 @@ begin Result := Plugins[Index].Procs.Load(@PluginInterface); except Result := -3; - End; + end; if (Result = 0) then Plugins[Index].State := 1 @@ -432,7 +433,7 @@ begin begin FreePlugin(Index); Plugins[Index].State := 255; - Core.ReportError(integer(PChar('Error calling load function from plugin: ' + String(Plugins[Index].Info.Name))), PChar('TPluginLoader')); + Core.ReportError(integer(PChar('Error calling load function from plugin: ' + string(Plugins[Index].Info.Name))), PChar('TPluginLoader')); end; end; end; @@ -441,7 +442,7 @@ end; //-------------- // Calls init func of plugin with the given index //-------------- -function TPluginLoader.CallInit(Index: Cardinal): integer; +function TPluginLoader.CallInit(Index: integer): integer; begin Result := -2; if(Index < Length(Plugins)) then @@ -452,18 +453,18 @@ begin Result := Plugins[Index].Procs.Init(@PluginInterface); except Result := -3; - End; - + end; + if (Result = 0) then begin Plugins[Index].State := 2; - Plugins[Index].NeedsDeInit := True; + Plugins[Index].NeedsDeInit := true; end else begin FreePlugin(Index); Plugins[Index].State := 255; - Core.ReportError(integer(PChar('Error calling init function from plugin: ' + String(Plugins[Index].Info.Name))), PChar('TPluginLoader')); + Core.ReportError(integer(PChar('Error calling init function from plugin: ' + string(Plugins[Index].Info.Name))), PChar('TPluginLoader')); end; end; end; @@ -472,7 +473,7 @@ end; //-------------- // Calls deinit proc of plugin with the given index //-------------- -procedure TPluginLoader.CallDeInit(Index: Cardinal); +procedure TPluginLoader.CallDeInit(Index: integer); begin if(Index < Length(Plugins)) then begin @@ -483,7 +484,7 @@ begin Plugins[Index].Procs.DeInit(@PluginInterface); except - End; + end; // Don't forget to remove services and subscriptions by this plugin Core.Hooks.DelbyOwner(-1 - Index); @@ -496,7 +497,7 @@ end; //-------------- // Frees all plugin sources (procs and handles) - helper for deiniting functions //-------------- -procedure TPluginLoader.FreePlugin(Index: Cardinal); +procedure TPluginLoader.FreePlugin(Index: integer); begin Plugins[Index].State := 4; Plugins[Index].Procs.Load := nil; @@ -507,15 +508,13 @@ begin FreeLibrary(Plugins[Index].hLib); end; - - //-------------- // wParam PChar(PluginName/PluginPath) | wParam (if lParam = nil) ID of the plugin //-------------- function TPluginLoader.LoadPlugin(wParam: TwParam; lParam: TlParam): integer; var Index: integer; - sFile: String; + sFile: string; begin Result := -1; sFile := ''; @@ -527,9 +526,9 @@ begin else begin //lParam is PChar try - sFile := String(PChar(lParam)); + sFile := string(PChar(lParam)); Index := PluginExists(sFile); - if (Index < 0) And FileExists(sFile) then + if (Index < 0) and FileExists(sFile) then begin // Is filename AddPlugin(sFile); Result := Plugins[High(Plugins)].State; @@ -539,7 +538,6 @@ begin end; end; - if (Index >= 0) and (Index < Length(Plugins)) then begin AddPlugin(Plugins[Index].Path); @@ -553,7 +551,7 @@ end; function TPluginLoader.UnloadPlugin(wParam: TwParam; lParam: TlParam): integer; var Index: integer; - sName: String; + sName: string; begin Result := -1; // lParam is ID @@ -564,14 +562,13 @@ begin else begin // wParam is PChar try - sName := String(PChar(lParam)); + sName := string(PChar(lParam)); Index := PluginExists(sName); except Index := -2; end; end; - if (Index >= 0) and (Index < Length(Plugins)) then CallDeInit(Index) end; @@ -592,7 +589,7 @@ begin PUS_PluginInfo(lParam)^ := Plugins[wParam].Info; except - End; + end; end; end else if (lParam = nil) then @@ -607,13 +604,13 @@ begin Result := Length(Plugins); except Core.ReportError(integer(PChar('Could not write PluginInfo Array')), PChar('TPluginLoader')); - End; + end; end; end; //-------------- -// if wParam = -1 then (if lParam = nil then get length of plugin state array. if lparam <> nil then write array of Byte to address at lparam) else (return state of plugin with index(wParam)) +// if wParam = -1 then (if lParam = nil then get length of plugin state array. if lparam <> nil then write array of byte to address at lparam) else (return state of plugin with index(wParam)) //-------------- function TPluginLoader.GetPluginState(wParam: TwParam; lParam: TlParam): integer; var I: integer; @@ -634,15 +631,14 @@ begin begin try for I := 0 to high(Plugins) do - Byte(Pointer(integer(lParam) + I)^) := Plugins[I].State; + byte(Pointer(integer(lParam) + I)^) := Plugins[I].State; Result := Length(Plugins); except Core.ReportError(integer(PChar('Could not write pluginstate array')), PChar('TPluginLoader')); - End; + end; end; end; - {********************* TtehPlugins Implementation @@ -673,7 +669,7 @@ end; // to offer them to other modules or plugins during the init process // if false is returned this will cause a forced exit //------------- -function TtehPlugins.Load: Boolean; +function TtehPlugins.Load: boolean; var i: integer; // Counter CurExecutedBackup: integer; //backup of Core.CurExecuted Attribute @@ -703,11 +699,11 @@ begin begin PluginLoader.CallDeInit(i); PluginLoader.Plugins[i].State := 254; // Plugin asks for unload - Core.ReportDebug(integer(PChar('Plugin selfabort during loading process: ' + String(PluginLoader.Plugins[i].Info.Name))), PChar('TtehPlugins')); + Core.ReportDebug(integer(PChar('Plugin selfabort during loading process: ' + string(PluginLoader.Plugins[i].Info.Name))), PChar('TtehPlugins')); end else begin - Core.ReportDebug(integer(PChar('Plugin loaded succesfully: ' + String(PluginLoader.Plugins[i].Info.Name))), PChar('TtehPlugins')); + Core.ReportDebug(integer(PChar('Plugin loaded succesfully: ' + string(PluginLoader.Plugins[i].Info.Name))), PChar('TtehPlugins')); end; except // Plugin could not be loaded. @@ -721,7 +717,7 @@ begin end; end; - // Reset CurExecuted + // Reset CurExecuted Core.CurExecuted := CurExecutedBackup; end; end; @@ -732,7 +728,7 @@ end; // your classes, variables etc. // if false is returned this will cause a forced exit //------------- -function TtehPlugins.Init: Boolean; +function TtehPlugins.Init: boolean; var i: integer; // Counter CurExecutedBackup: integer; // backup of Core.CurExecuted attribute @@ -752,16 +748,16 @@ begin begin PluginLoader.CallDeInit(i); PluginLoader.Plugins[i].State := 254; //Plugin asks for unload - Core.ReportDebug(integer(PChar('Plugin selfabort during init process: ' + String(PluginLoader.Plugins[i].Info.Name))), PChar('TtehPlugins')); + Core.ReportDebug(integer(PChar('Plugin selfabort during init process: ' + string(PluginLoader.Plugins[i].Info.Name))), PChar('TtehPlugins')); end else - Core.ReportDebug(integer(PChar('Plugin inited succesfully: ' + String(PluginLoader.Plugins[i].Info.Name))), PChar('TtehPlugins')); + Core.ReportDebug(integer(PChar('Plugin inited succesfully: ' + string(PluginLoader.Plugins[i].Info.Name))), PChar('TtehPlugins')); except // Plugin could not be loaded. // => Show error message, then shut down plugin PluginLoader.CallDeInit(i); PluginLoader.Plugins[i].State := 255; //Plugin causes Error - Core.ReportError(integer(PChar('Plugin causes error during init process: ' + String(PluginLoader.Plugins[i].Info.Name))), PChar('TtehPlugins')); + Core.ReportError(integer(PChar('Plugin causes error during init process: ' + string(PluginLoader.Plugins[i].Info.Name))), PChar('TtehPlugins')); end; // Reset CurExecuted @@ -781,7 +777,7 @@ begin CurExecutedBackup := Core.CurExecuted; // Start loop - + for i := 0 to High(PluginLoader.Plugins) do begin try diff --git a/unicode/src/base/URecord.pas b/unicode/src/base/URecord.pas index 132bafd5..8f37262d 100644 --- a/unicode/src/base/URecord.pas +++ b/unicode/src/base/URecord.pas @@ -36,26 +36,26 @@ interface uses Classes, Math, - SysUtils, sdl, + SysUtils, UCommon, UMusic, UIni; const BaseToneFreq = 65.4064; // lowest (half-)tone to analyze (C2 = 65.4064 Hz) - NumHalftones = 36; // C2-B4 (for Whitney and my high voice) + NumHalftones = 36; // C2-B4 (for Whitney and my high voice) type TCaptureBuffer = class private - VoiceStream: TAudioVoiceStream; // stream for voice passthrough + VoiceStream: TAudioVoiceStream; // stream for voice passthrough AnalysisBufferLock: PSDL_Mutex; function GetToneString: string; // converts a tone to its string represenatation; - procedure BoostBuffer(Buffer: PChar; Size: Cardinal); - procedure ProcessNewBuffer(Buffer: PChar; BufferSize: integer); + procedure BoostBuffer(Buffer: PByteArray; Size: cardinal); + procedure ProcessNewBuffer(Buffer: PByteArray; BufferSize: integer); // we call it to analyze sound by checking Autocorrelation procedure AnalyzeByAutocorrelation; @@ -86,7 +86,7 @@ type procedure LockAnalysisBuffer(); {$IFDEF HasInline}inline;{$ENDIF} procedure UnlockAnalysisBuffer(); {$IFDEF HasInline}inline;{$ENDIF} - function MaxSampleVolume: Single; + function MaxSampleVolume: single; property ToneString: string READ GetToneString; end; @@ -95,17 +95,17 @@ const type TAudioInputSource = record - Name: string; + Name: string; end; // soundcard input-devices information TAudioInputDevice = class public - CfgIndex: integer; // index of this device in Ini.InputDeviceConfig - Name: string; // soundcard name - Source: array of TAudioInputSource; // soundcard input-sources - SourceRestore: integer; // source-index that will be selected after capturing (-1: not detected) - MicSource: integer; // source-index of mic (-1: none detected) + CfgIndex: integer; // index of this device in Ini.InputDeviceConfig + Name: string; // soundcard name + Source: array of TAudioInputSource; // soundcard input-sources + SourceRestore: integer; // source-index that will be selected after capturing (-1: not detected) + MicSource: integer; // source-index of mic (-1: none detected) AudioFormat: TAudioFormatInfo; // capture format info (e.g. 44.1kHz SInt16 stereo) CaptureChannel: array of TCaptureBuffer; // sound-buffer references used for mono or stereo channel's capture data @@ -115,10 +115,10 @@ type procedure LinkCaptureBuffer(ChannelIndex: integer; Sound: TCaptureBuffer); // TODO: add Open/Close functions so Start/Stop becomes faster - //function Open(): boolean; virtual; abstract; - //function Close(): boolean; virtual; abstract; - function Start(): boolean; virtual; abstract; - function Stop(): boolean; virtual; abstract; + //function Open(): boolean; virtual; abstract; + //function Close(): boolean; virtual; abstract; + function Start(): boolean; virtual; abstract; + function Stop(): boolean; virtual; abstract; function GetVolume(): single; virtual; abstract; procedure SetVolume(Volume: single); virtual; abstract; @@ -135,7 +135,7 @@ type procedure UpdateInputDeviceConfig; // handle microphone input - procedure HandleMicrophoneData(Buffer: PChar; Size: Cardinal; + procedure HandleMicrophoneData(Buffer: PByteArray; Size: cardinal; InputDevice: TAudioInputDevice); end; @@ -153,7 +153,6 @@ type procedure CaptureStop; end; - TSmallIntArray = array [0..(MaxInt div SizeOf(SmallInt))-1] of SmallInt; PSmallIntArray = ^TSmallIntArray; @@ -163,12 +162,11 @@ implementation uses ULog, - UMain; + UNote; var singleton_AudioInputProcessor : TAudioInputProcessor = nil; - { Global } function AudioInputProcessor(): TAudioInputProcessor; @@ -179,7 +177,6 @@ begin result := singleton_AudioInputProcessor; end; - { TAudioInputDevice } destructor TAudioInputDevice.Destroy; @@ -268,11 +265,11 @@ begin UnlockAnalysisBuffer(); end; -procedure TCaptureBuffer.ProcessNewBuffer(Buffer: PChar; BufferSize: integer); +procedure TCaptureBuffer.ProcessNewBuffer(Buffer: PByteArray; BufferSize: integer); var BufferOffset: integer; - SampleCount: integer; - i: integer; + SampleCount: integer; + i: integer; begin // apply software boost BoostBuffer(Buffer, BufferSize); @@ -299,7 +296,6 @@ begin SampleCount := Length(AnalysisBuffer); end; - LockAnalysisBuffer(); try @@ -315,7 +311,6 @@ begin UnlockAnalysisBuffer(); end; - // save capture-data to BufferLong if enabled if (Ini.SavePlayback = 1) then begin @@ -329,10 +324,10 @@ end; procedure TCaptureBuffer.AnalyzeBuffer; var - Volume: single; - MaxVolume: single; + Volume: single; + MaxVolume: single; SampleIndex: integer; - Threshold: single; + Threshold: single; begin ToneValid := false; ToneAbs := -1; @@ -431,10 +426,10 @@ begin Result := 1 - AccumDist / AnalysisBufferSize; end; -function TCaptureBuffer.MaxSampleVolume: Single; +function TCaptureBuffer.MaxSampleVolume: single; var - lSampleIndex: Integer; - lMaxVol : Longint; + lSampleIndex: integer; + lMaxVol: longint; begin; LockAnalysisBuffer(); try @@ -464,13 +459,13 @@ begin Result := '-'; end; -procedure TCaptureBuffer.BoostBuffer(Buffer: PChar; Size: Cardinal); +procedure TCaptureBuffer.BoostBuffer(Buffer: PByteArray; Size: cardinal); var - i: integer; - Value: Longint; - SampleCount: integer; + i: integer; + Value: longint; + SampleCount: integer; SampleBuffer: PSmallIntArray; // buffer handled as array of samples - Boost: byte; + Boost: byte; begin // TODO: set boost per device case Ini.MicBoost of @@ -504,7 +499,6 @@ begin end; end; - { TAudioInputProcessor } constructor TAudioInputProcessor.Create; @@ -531,14 +525,14 @@ end; // See: TIni.LoadInputDeviceCfg() procedure TAudioInputProcessor.UpdateInputDeviceConfig; var - deviceIndex: integer; - newDevice: boolean; + deviceIndex: integer; + newDevice: boolean; deviceIniIndex: integer; - deviceCfg: PInputDeviceConfig; - device: TAudioInputDevice; - channelCount: integer; - channelIndex: integer; - i: integer; + deviceCfg: PInputDeviceConfig; + device: TAudioInputDevice; + channelCount: integer; + channelIndex: integer; + i: integer; begin // Input devices - append detected soundcards for deviceIndex := 0 to High(DeviceList) do @@ -608,18 +602,18 @@ end; * Length - number of bytes in Buffer * Input - Soundcard-Input used for capture *} -procedure TAudioInputProcessor.HandleMicrophoneData(Buffer: PChar; Size: Cardinal; InputDevice: TAudioInputDevice); +procedure TAudioInputProcessor.HandleMicrophoneData(Buffer: PByteArray; Size: cardinal; InputDevice: TAudioInputDevice); var - MultiChannelBuffer: PChar; // buffer handled as array of bytes (offset relative to channel) - SingleChannelBuffer: PChar; // temporary buffer for new samples per channel + MultiChannelBuffer: PByteArray; // buffer handled as array of bytes (offset relative to channel) + SingleChannelBuffer: PByteArray; // temporary buffer for new samples per channel SingleChannelBufferSize: integer; - ChannelIndex: integer; - CaptureChannel: TCaptureBuffer; - AudioFormat: TAudioFormatInfo; - SampleSize: integer; - SampleCount: integer; - SamplesPerChannel: integer; - i: integer; + ChannelIndex: integer; + CaptureChannel: TCaptureBuffer; + AudioFormat: TAudioFormatInfo; + SampleSize: integer; + SampleCount: integer; + SamplesPerChannel: integer; + i: integer; begin AudioFormat := InputDevice.AudioFormat; SampleSize := AudioSampleSize[AudioFormat.Format]; @@ -638,7 +632,7 @@ begin begin // set offset according to channel index MultiChannelBuffer := @Buffer[ChannelIndex * SampleSize]; - // seperate channel-data from interleaved multi-channel (e.g. stereo) data + // separate channel-data from interleaved multi-channel (e.g. stereo) data for i := 0 to SamplesPerChannel-1 do begin Move(MultiChannelBuffer[i*AudioFormat.FrameSize], @@ -652,7 +646,6 @@ begin FreeMem(SingleChannelBuffer); end; - { TAudioInputBase } function TAudioInputBase.FinalizeRecord: boolean; @@ -670,13 +663,13 @@ end; *} procedure TAudioInputBase.CaptureStart; var - S: integer; - DeviceIndex: integer; + S: integer; + DeviceIndex: integer; ChannelIndex: integer; - Device: TAudioInputDevice; - DeviceCfg: PInputDeviceConfig; - DeviceUsed: boolean; - Player: integer; + Device: TAudioInputDevice; + DeviceCfg: PInputDeviceConfig; + DeviceUsed: boolean; + Player: integer; begin if (Started) then CaptureStop(); @@ -728,10 +721,10 @@ end; *} procedure TAudioInputBase.CaptureStop; var - DeviceIndex: integer; + DeviceIndex: integer; ChannelIndex: integer; - Device: TAudioInputDevice; - DeviceCfg: PInputDeviceConfig; + Device: TAudioInputDevice; + DeviceCfg: PInputDeviceConfig; begin for DeviceIndex := 0 to High(AudioInputProcessor.DeviceList) do begin @@ -758,17 +751,18 @@ var var i: integer; begin - Result := False; + Result := false; // search devices with same description - For i := 0 to deviceIndex-1 do + for i := 0 to deviceIndex-1 do begin if (AudioInputProcessor.DeviceList[i].Name = name) then begin - Result := True; + Result := true; Break; end; end; end; + begin count := 1; result := name; @@ -783,6 +777,3 @@ begin end; end. - - - diff --git a/unicode/src/base/URingBuffer.pas b/unicode/src/base/URingBuffer.pas index 515d0efb..684c13ee 100644 --- a/unicode/src/base/URingBuffer.pas +++ b/unicode/src/base/URingBuffer.pas @@ -39,7 +39,7 @@ uses type TRingBuffer = class private - RingBuffer: PChar; + RingBuffer: PByteArray; BufferCount: integer; BufferSize: integer; WritePos: integer; @@ -47,8 +47,10 @@ type public constructor Create(Size: integer); destructor Destroy; override; - function Read(Buffer: PChar; Count: integer): integer; - function Write(Buffer: PChar; Count: integer): integer; + function Read(Buffer: PByteArray; Count: integer): integer; + function Write(Buffer: PByteArray; Count: integer): integer; + function Size(): integer; + function Available(): integer; procedure Flush(); end; @@ -71,7 +73,7 @@ begin FreeMem(RingBuffer); end; -function TRingBuffer.Read(Buffer: PChar; Count: integer): integer; +function TRingBuffer.Read(Buffer: PByteArray; Count: integer): integer; var PartCount: integer; begin @@ -106,7 +108,7 @@ begin Result := Count; end; -function TRingBuffer.Write(Buffer: PChar; Count: integer): integer; +function TRingBuffer.Write(Buffer: PByteArray; Count: integer): integer; var PartCount: integer; begin @@ -143,6 +145,16 @@ begin Result := Count; end; +function TRingBuffer.Available(): integer; +begin + Result := BufferCount; +end; + +function TRingBuffer.Size(): integer; +begin + Result := BufferSize; +end; + procedure TRingBuffer.Flush(); begin ReadPos := 0; @@ -150,4 +162,4 @@ begin BufferCount := 0; end; -end.
\ No newline at end of file +end. diff --git a/unicode/src/base/USkins.pas b/unicode/src/base/USkins.pas index df736684..a4722d95 100644 --- a/unicode/src/base/USkins.pas +++ b/unicode/src/base/USkins.pas @@ -35,23 +35,23 @@ interface type TSkinTexture = record - Name: string; - FileName: string; + Name: string; + FileName: string; end; TSkinEntry = record - Theme: string; - Name: string; - Path: string; - FileName: string; - Creator: string; // not used yet + Theme: string; + Name: string; + Path: string; + FileName: string; + Creator: string; // not used yet end; TSkin = class - Skin: array of TSkinEntry; - SkinTexture: array of TSkinTexture; - SkinPath: string; - Color: integer; + Skin: array of TSkinEntry; + SkinTexture: array of TSkinTexture; + SkinPath: string; + Color: integer; constructor Create; procedure LoadList; procedure ParseDir(Dir: string); @@ -63,30 +63,33 @@ type end; var - Skin: TSkin; + Skin: TSkin; implementation -uses IniFiles, - Classes, - SysUtils, - UMain, - ULog, - UIni; +uses + IniFiles, + Classes, + SysUtils, + UIni, + ULog, + UMain, + UPath; constructor TSkin.Create; begin inherited; LoadList; -// LoadSkin('Lisek'); +// LoadSkin('...'); // SkinColor := Color; end; procedure TSkin.LoadList; var - SR: TSearchRec; + SR: TSearchRec; begin - if FindFirst(SkinsPath+'*', faDirectory, SR) = 0 then begin + if FindFirst(SkinsPath+'*', faDirectory, SR) = 0 then + begin repeat if (SR.Name <> '.') and (SR.Name <> '..') then ParseDir(SkinsPath + SR.Name + PathDelim); @@ -97,9 +100,10 @@ end; procedure TSkin.ParseDir(Dir: string); var - SR: TSearchRec; + SR: TSearchRec; begin - if FindFirst(Dir + '*.ini', faAnyFile, SR) = 0 then begin + if FindFirst(Dir + '*.ini', faAnyFile, SR) = 0 then + begin repeat if (SR.Name <> '.') and (SR.Name <> '..') then @@ -111,8 +115,8 @@ end; procedure TSkin.LoadHeader(FileName: string); var - SkinIni: TMemIniFile; - S: integer; + SkinIni: TMemIniFile; + S: integer; begin SkinIni := TMemIniFile.Create(FileName); @@ -130,10 +134,10 @@ end; procedure TSkin.LoadSkin(Name: string); var - SkinIni: TMemIniFile; - SL: TStringList; - T: integer; - S: integer; + SkinIni: TMemIniFile; + SL: TStringList; + T: integer; + S: integer; begin S := GetSkinNumber(Name); SkinPath := Skin[S].Path; @@ -156,39 +160,43 @@ end; function TSkin.GetTextureFileName(TextureName: string): string; var - T: integer; + T: integer; begin Result := ''; for T := 0 to High(SkinTexture) do begin - if ( SkinTexture[T].Name = TextureName ) AND + if ( SkinTexture[T].Name = TextureName ) and ( SkinTexture[T].FileName <> '' ) then begin Result := SkinPath + SkinTexture[T].FileName; end; end; - if ( TextureName <> '' ) AND - ( Result <> '' ) THEN + if ( TextureName <> '' ) and + ( Result <> '' ) then begin //Log.LogError('', '-----------------------------------------'); //Log.LogError(TextureName+' - '+ Result, 'TSkin.GetTextureFileName'); end; { Result := SkinPath + 'Bar.jpg'; - if TextureName = 'Ball' then Result := SkinPath + 'Ball.bmp'; - if Copy(TextureName, 1, 4) = 'Gray' then Result := SkinPath + 'Ball.bmp'; - if Copy(TextureName, 1, 6) = 'NoteBG' then Result := SkinPath + 'Ball.bmp';} + if TextureName = 'Ball' then + Result := SkinPath + 'Ball.bmp'; + if Copy(TextureName, 1, 4) = 'Gray' then + Result := SkinPath + 'Ball.bmp'; + if Copy(TextureName, 1, 6) = 'NoteBG' then + Result := SkinPath + 'Ball.bmp';} end; function TSkin.GetSkinNumber(Name: string): integer; var - S: integer; + S: integer; begin Result := 0; // set default to the first available skin for S := 0 to High(Skin) do - if Skin[S].Name = Name then Result := S; + if Skin[S].Name = Name then + Result := S; end; procedure TSkin.onThemeChange; @@ -200,7 +208,8 @@ begin SetLength(ISkin, 0); Name := Uppercase(ITheme[Ini.Theme]); for S := 0 to High(Skin) do - if Name = Uppercase(Skin[S].Theme) then begin + if Name = Uppercase(Skin[S].Theme) then + begin SetLength(ISkin, Length(ISkin)+1); ISkin[High(ISkin)] := Skin[S].Name; end; diff --git a/unicode/src/base/USong.pas b/unicode/src/base/USong.pas index 69c6615d..a547a077 100644 --- a/unicode/src/base/USong.pas +++ b/unicode/src/base/USong.pas @@ -74,7 +74,7 @@ type end; TSong = class - FileLineNo : integer; //Line which is readed at Last, for error reporting + FileLineNo : integer; // line, which is read last, for error reporting function EncodeFilename(Filename: string): string; function Solmizate(Note: integer; Type_: integer): string; @@ -135,8 +135,8 @@ type MultBPM : integer; LastError: AnsiString; - Function GetErrorLineNo: Integer; - Property ErrorLineNo: Integer read GetErrorLineNo; + function GetErrorLineNo: integer; + property ErrorLineNo: integer read GetErrorLineNo; constructor Create(); overload; @@ -151,17 +151,54 @@ type implementation uses + StrUtils, TextGL, UIni, + UPath, UMusic, //needed for Lines - UMain; //needed for Player + UNote; //needed for Player constructor TSong.Create(); begin inherited; end; -constructor TSong.Create( const aFileName : WideString ); +constructor TSong.Create( const aFileName: WideString ); + // This may be changed, when we rewrite song select code. + // it is some kind of dirty, but imho the best possible + // solution as we do atm not support nested categorys. + // it works like the folder sorting in 1.0.1a + // folder is set to the first folder under the songdir + // so songs ~/.ultrastardx/songs/punk is in the same + // category as songs in shared/ultrastardx/songs are. + // note: folder is just the name of a category it has + // nothing to do with the path used for file loading + function GetFolderCategory: WideString; + var + I: Integer; + P: Integer; //position of next path delimiter + begin + Result := 'Unknown'; //default folder category, if we can't locate the song dir + + for I := 0 to SongPaths.Count-1 do + if (AnsiStartsText(SongPaths.Strings[I], aFilename)) then + begin + P := PosEx(PathDelim, aFilename, Length(SongPaths.Strings[I]) + 1); + + If (P > 0) then + begin + // we have found the category name => get it + Result := copy(self.Path, Length(SongPaths.Strings[I]) + 1, P - Length(SongPaths.Strings[I]) - 1); + end + else + begin + // songs are in the "root" of the songdir => use songdir for the categorys name + Result := SongPaths.Strings[I]; + end; + + Exit; + end; + end; begin inherited Create(); @@ -174,7 +211,7 @@ begin if fileexists( aFileName ) then begin self.Path := ExtractFilePath( aFileName ); - self.Folder := ExtractFilePath( aFileName ); + self.Folder := GetFolderCategory; self.FileName := ExtractFileName( aFileName ); (* if ReadTXTHeader( aFileName ) then @@ -229,9 +266,6 @@ begin MultBPM := 4; // multiply beat-count of note by 4 Mult := 1; // accuracy of measurement of note - Base[0] := 100; // high number - Lines[0].ScoreValue := 0; - self.Relative := false; Rel[0] := 0; CP := 0; Both := false; @@ -271,20 +305,24 @@ begin SetLength(Lines, 2); for Count := 0 to High(Lines) do begin - SetLength(Lines[Count].Line, 1); Lines[Count].High := 0; Lines[Count].Number := 1; Lines[Count].Current := 0; Lines[Count].Resolution := self.Resolution; Lines[Count].NotesGAP := self.NotesGAP; + Lines[Count].ScoreValue := 0; + + //Add first line and set some standard values to fields + //see procedure NewSentence for further explantation + //concerning most of these values + SetLength(Lines[Count].Line, 1); Lines[Count].Line[0].HighNote := -1; - Lines[Count].Line[0].LastLine := False; + Lines[Count].Line[0].LastLine := false; + Lines[Count].Line[0].BaseNote := High(Integer); + Lines[Count].Line[0].TotalNotes := 0; end; - //TempC := ':'; - //TempC := Text[1]; // read from backup variable, don't use default ':' value - - while (TempC <> 'E') AND (not EOF(SongFile)) do + while (TempC <> 'E') and (not EOF(SongFile)) do begin if (TempC = ':') or (TempC = '*') or (TempC = 'F') then @@ -296,13 +334,16 @@ begin Read(SongFile, ParamS); //Check for ZeroNote - if Param2 = 0 then Log.LogError('Found ZeroNote at "'+TempC+' '+IntToStr(Param1)+' '+IntToStr(Param2)+' '+IntToStr(Param3)+ParamS+'" -> Note ignored!') else + if Param2 = 0 then + Log.LogError('Found ZeroNote at "'+TempC+' '+IntToStr(Param1)+' '+IntToStr(Param2)+' '+IntToStr(Param3)+ParamS+'" -> Note ignored!') + else begin // add notes if not Both then // P1 ParseNote(0, TempC, (Param1+Rel[0]) * Mult, Param2 * Mult, Param3, ParamS) - else begin + else + begin // P1 + P2 ParseNote(0, TempC, (Param1+Rel[0]) * Mult, Param2 * Mult, Param3, ParamS); ParseNote(1, TempC, (Param1+Rel[1]) * Mult, Param2 * Mult, Param3, ParamS); @@ -310,24 +351,26 @@ begin end; //Zeronote check end // if - Else if TempC = '-' then + else if TempC = '-' then begin // reads sentence Read(SongFile, Param1); - if self.Relative then Read(SongFile, Param2); // read one more data for relative system + if self.Relative then + Read(SongFile, Param2); // read one more data for relative system // new sentence if not Both then // P1 NewSentence(0, (Param1 + Rel[0]) * Mult, Param2) - else begin + else + begin // P1 + P2 NewSentence(0, (Param1 + Rel[0]) * Mult, Param2); NewSentence(1, (Param1 + Rel[1]) * Mult, Param2); end; end // if - Else if TempC = 'B' then + else if TempC = 'B' then begin SetLength(self.BPM, Length(self.BPM) + 1); Read(SongFile, self.BPM[High(self.BPM)].StartBeat); @@ -338,42 +381,7 @@ begin self.BPM[High(self.BPM)].BPM := self.BPM[High(self.BPM)].BPM * Mult * MultBPM; end; - - if not Both then - begin - Lines[CP].Line[Lines[CP].High].BaseNote := Base[CP]; - Lines[CP].Line[Lines[CP].High].LyricWidth := glTextWidth(Lines[CP].Line[Lines[CP].High].Lyric); - //Total Notes Patch - Lines[CP].Line[Lines[CP].High].TotalNotes := 0; - for I := low(Lines[CP].Line[Lines[CP].High].Note) to high(Lines[CP].Line[Lines[CP].High].Note) do - begin - if (Lines[CP].Line[Lines[CP].High].Note[I].NoteType = ntGolden) then - Lines[CP].Line[Lines[CP].High].TotalNotes := Lines[CP].Line[Lines[CP].High].TotalNotes + Lines[CP].Line[Lines[CP].High].Note[I].Length; - - if (Lines[CP].Line[Lines[CP].High].Note[I].NoteType <> ntFreestyle) then - Lines[CP].Line[Lines[CP].High].TotalNotes := Lines[CP].Line[Lines[CP].High].TotalNotes + Lines[CP].Line[Lines[CP].High].Note[I].Length; - end; - //Total Notes Patch End - end - else - begin - for Count := 0 to High(Lines) do - begin - Lines[Count].Line[Lines[Count].High].BaseNote := Base[Count]; - Lines[Count].Line[Lines[Count].High].LyricWidth := glTextWidth(Lines[Count].Line[Lines[Count].High].Lyric); - //Total Notes Patch - Lines[Count].Line[Lines[Count].High].TotalNotes := 0; - for I := low(Lines[Count].Line[Lines[Count].High].Note) to high(Lines[Count].Line[Lines[Count].High].Note) do - begin - if (Lines[Count].Line[Lines[Count].High].Note[I].NoteType = ntGolden) then - Lines[Count].Line[Lines[Count].High].TotalNotes := Lines[Count].Line[Lines[Count].High].TotalNotes + Lines[Count].Line[Lines[Count].High].Note[I].Length; - if (Lines[Count].Line[Lines[Count].High].Note[I].NoteType <> ntFreestyle) then - Lines[Count].Line[Lines[Count].High].TotalNotes := Lines[Count].Line[Lines[Count].High].TotalNotes + Lines[Count].Line[Lines[Count].High].Note[I].Length; - end; - //Total Notes Patch End - end; - end; - ReadLn(SongFile); //Jump to next line in File, otherwise the next Read would catch the linebreak(e.g. #13 #10 on win32) + ReadLn(SongFile); //Jump to next line in File, otherwise the next Read would catch the linebreak(e.g. #13 #10 on win32) Read(SongFile, TempC); Inc(FileLineNo); @@ -381,18 +389,18 @@ begin CloseFile(SongFile); - For I := 0 to High(Lines) do + for I := 0 to High(Lines) do begin - If ((Both) or (I = 0)) then + if ((Both) or (I = 0)) then begin - If (Length(Lines[I].Line) < 2) then + if (Length(Lines[I].Line) < 2) then begin LastError := 'ERROR_CORRUPT_SONG_NO_BREAKS'; Log.LogError('Error Loading File, Can''t find any Linebreaks: "' + fFileName + '"'); exit; end; - If (Lines[I].Line[Lines[I].High].HighNote < 0) then + if (Lines[I].Line[Lines[I].High].HighNote < 0) then begin SetLength(Lines[I].Line, Lines[I].Number - 1); Lines[I].High := Lines[I].High - 1; @@ -404,8 +412,8 @@ begin for Count := 0 to High(Lines) do begin - If (High(Lines[Count].Line) >= 0) then - Lines[Count].Line[High(Lines[Count].Line)].LastLine := True; + if (High(Lines[Count].Line) >= 0) then + Lines[Count].Line[High(Lines[Count].Line)].LastLine := true; end; except try @@ -452,7 +460,6 @@ begin MultBPM := 4; // multiply beat-count of note by 4 Mult := 1; // accuracy of measurement of note - Base[0] := 100; // high number Lines[0].ScoreValue := 0; self.Relative := false; Rel[0] := 0; @@ -467,14 +474,21 @@ begin for Count := 0 to High(Lines) do begin - SetLength(Lines[Count].Line, 1); Lines[Count].High := 0; - Lines[Count].Number := 1; - Lines[Count].Current := 0; - Lines[Count].Resolution := self.Resolution; - Lines[Count].NotesGAP := self.NotesGAP; - Lines[Count].Line[0].HighNote := -1; - Lines[Count].Line[0].LastLine := False; + Lines[Count].Number := 1; + Lines[Count].Current := 0; + Lines[Count].Resolution := self.Resolution; + Lines[Count].NotesGAP := self.NotesGAP; + Lines[Count].ScoreValue := 0; + + //Add first line and set some standard values to fields + //see procedure NewSentence for further explantation + //concerning most of these values + SetLength(Lines[Count].Line, 1); + Lines[Count].Line[0].HighNote := -1; + Lines[Count].Line[0].LastLine := false; + Lines[Count].Line[0].BaseNote := High(Integer); + Lines[Count].Line[0].TotalNotes := 0; end; //Try to Parse the Song @@ -482,7 +496,7 @@ begin if Parser.ParseSong(Path + PathDelim + FileName) then begin //Writeln('XML Inputfile Parsed succesful'); - + //Start write parsed information to Song //Notes Part for I := 0 to High(Parser.SongInfo.Sentences) do @@ -491,8 +505,8 @@ begin for J := 0 to High(Parser.SongInfo.Sentences[I].Notes) do begin case Parser.SongInfo.Sentences[I].Notes[J].NoteTyp of - NT_Normal: NoteType := ':'; - NT_Golden: NoteType := '*'; + NT_Normal: NoteType := ':'; + NT_Golden: NoteType := '*'; NT_Freestyle: NoteType := 'F'; end; @@ -511,42 +525,6 @@ begin ParseNote(1, NoteType, (Param1+Rel[1]) * Mult, Param2 * Mult, Param3, ParamS); end; - if not Both then - begin - Lines[CP].Line[Lines[CP].High].BaseNote := Base[CP]; - Lines[CP].Line[Lines[CP].High].LyricWidth := glTextWidth(Lines[CP].Line[Lines[CP].High].Lyric); - //Total Notes Patch - Lines[CP].Line[Lines[CP].High].TotalNotes := 0; - for NoteIndex := 0 to high(Lines[CP].Line[Lines[CP].High].Note) do - begin - if (Lines[CP].Line[Lines[CP].High].Note[NoteIndex].NoteType = ntGolden) then - Lines[CP].Line[Lines[CP].High].TotalNotes := Lines[CP].Line[Lines[CP].High].TotalNotes + Lines[CP].Line[Lines[CP].High].Note[NoteIndex].Length; - - if (Lines[CP].Line[Lines[CP].High].Note[NoteIndex].NoteType <> ntFreestyle) then - Lines[CP].Line[Lines[CP].High].TotalNotes := Lines[CP].Line[Lines[CP].High].TotalNotes + Lines[CP].Line[Lines[CP].High].Note[NoteIndex].Length; - end; - //Total Notes Patch End - end - else - begin - for Count := 0 to High(Lines) do - begin - Lines[Count].Line[Lines[Count].High].BaseNote := Base[Count]; - Lines[Count].Line[Lines[Count].High].LyricWidth := glTextWidth(Lines[Count].Line[Lines[Count].High].Lyric); - //Total Notes Patch - Lines[Count].Line[Lines[Count].High].TotalNotes := 0; - for NoteIndex := 0 to high(Lines[Count].Line[Lines[Count].High].Note) do - begin - if (Lines[Count].Line[Lines[Count].High].Note[NoteIndex].NoteType = ntGolden) then - Lines[Count].Line[Lines[Count].High].TotalNotes := Lines[Count].Line[Lines[Count].High].TotalNotes + Lines[Count].Line[Lines[Count].High].Note[NoteIndex].Length; - if (Lines[Count].Line[Lines[Count].High].Note[NoteIndex].NoteType <> ntFreestyle) then - Lines[Count].Line[Lines[Count].High].TotalNotes := Lines[Count].Line[Lines[Count].High].TotalNotes + Lines[Count].Line[Lines[Count].High].Note[NoteIndex].Length; - - end; - //Total Notes Patch End - end; - end; { end of for loop } - end; //J Forloop //Add Sentence break @@ -558,8 +536,8 @@ begin //Calculate Time case Rest of 0, 1: Time := Parser.SongInfo.Sentences[I+1].Notes[0].Start; - 2: Time := Parser.SongInfo.Sentences[I+1].Notes[0].Start - 1; - 3: Time := Parser.SongInfo.Sentences[I+1].Notes[0].Start - 2; + 2: Time := Parser.SongInfo.Sentences[I+1].Notes[0].Start - 1; + 3: Time := Parser.SongInfo.Sentences[I+1].Notes[0].Start - 2; else if (Rest >= 4) then Time := SentenceEnd + 2 @@ -588,7 +566,7 @@ begin for Count := 0 to High(Lines) do begin - Lines[Count].Line[High(Lines[Count].Line)].LastLine := True; + Lines[Count].Line[High(Lines[Count].Line)].LastLine := true; end; Result := true; @@ -670,7 +648,8 @@ begin //Language Sorting self.Language := Parser.SongInfo.Header.Language; - end else + end + else Log.LogError('File Incomplete or not SingStar XML (A): ' + aFileName); Parser.Free; @@ -678,7 +657,7 @@ begin //Check if all Required Values are given if (Done <> 15) then begin - Result := False; + Result := false; if (Done and 8) = 0 then //No BPM Flag Log.LogError('BPM Tag Missing: ' + self.FileName) else if (Done and 4) = 0 then //No MP3 Flag @@ -700,7 +679,7 @@ function TSong.ReadTXTHeader(const aFileName : WideString): boolean; * "International" StrToFloat variant. Uses either ',' or '.' as decimal * separator. *} - function StrToFloatI18n(const Value: string): Extended; + function StrToFloatI18n(const Value: string): extended; var TempValue : string; begin @@ -727,7 +706,7 @@ begin begin Log.LogError('File Starts with Empty Line: ' + Path + PathDelim + aFileName, 'TSong.ReadTXTHeader'); - Result := False; + Result := false; Exit; end; @@ -736,8 +715,7 @@ begin Encoding := encUTF8; //Read Lines while Line starts with # or its empty - while (Length(Line) = 0) or - (Line[1] = '#') do + while (Length(Line) = 0) or (Line[1] = '#') do begin //Increase Line Number Inc (FileLineNo); @@ -898,7 +876,7 @@ begin else if (Identifier = 'RELATIVE') then begin if (UpperCase(Value) = 'YES') then - self.Relative := True; + self.Relative := true; end // File encoding @@ -912,7 +890,7 @@ begin // check for end of file if Eof(SongFile) then begin - Result := False; + Result := false; Log.LogError('File Incomplete or not Ultrastar TxT (A): ' + aFileName); Break; end; @@ -927,7 +905,7 @@ begin //Check if all Required Values are given if (Done <> 15) then begin - Result := False; + Result := false; if (Done and 8) = 0 then //No BPM Flag Log.LogError('BPM Tag Missing: ' + self.FileName) else if (Done and 4) = 0 then //No MP3 Flag @@ -942,11 +920,11 @@ begin end; -Function TSong.GetErrorLineNo: Integer; +function TSong.GetErrorLineNo: integer; begin - If (LastError='ERROR_CORRUPT_SONG_ERROR_IN_LINE') then + if (LastError='ERROR_CORRUPT_SONG_ERROR_IN_LINE') then Result := FileLineNo - Else + else Result := -1; end; @@ -1001,7 +979,7 @@ begin begin SetLength(Note, Length(Note) + 1); HighNote := High(Note); - + Note[HighNote].Start := StartP; if HighNote = 0 then begin @@ -1019,18 +997,28 @@ begin '*': Note[HighNote].NoteType := ntGolden; end; - if (Note[HighNote].NoteType = ntGolden) then - Lines[LineNumber].ScoreValue := Lines[LineNumber].ScoreValue + Note[HighNote].Length; - - if (Note[HighNote].NoteType <> ntFreestyle) then - Lines[LineNumber].ScoreValue := Lines[LineNumber].ScoreValue + Note[HighNote].Length; + //add this notes value ("notes length" * "notes scorefactor") to the current songs entire value + Inc(Lines[LineNumber].ScoreValue, Note[HighNote].Length * ScoreFactor[Note[HighNote].NoteType]); + + //and to the current lines entire value + Inc(TotalNotes, Note[HighNote].Length * ScoreFactor[Note[HighNote].NoteType]); + Note[HighNote].Tone := NoteP; - if Note[HighNote].Tone < Base[LineNumber] then Base[LineNumber] := Note[HighNote].Tone; - Note[HighNote].Text := RecodeStringUTF8( - Copy(LyricS, 2, Length(LyricS)-1), - Encoding); + //if a note w/ a deeper pitch then the current basenote is found + //we replace the basenote w/ the current notes pitch + if Note[HighNote].Tone < BaseNote then + BaseNote := Note[HighNote].Tone; + + //delete the space that seperates the notes pitch from its lyrics + //it is left in the LyricS string because Read("some ordinal type") will + //set the files pointer to the first whitespace character after the + //ordinal string. Trim is no solution because it would cut the spaces + //that seperate the words of the lyrics, too. + Delete(LyricS, 1, 1); + + Note[HighNote].Text := RecodeStringUTF8(LyricS, Encoding); Lyric := Lyric + Note[HighNote].Text; End_ := Note[HighNote].Start + Note[HighNote].Length; @@ -1042,37 +1030,30 @@ var I: integer; begin - If (Lines[LineNumberP].Line[Lines[LineNumberP].High].HighNote <> -1) then - begin //Update old Sentence if it has notes and create a new sentence - // stara czesc //Alter Satz //Update Old Part - Lines[LineNumberP].Line[Lines[LineNumberP].High].BaseNote := Base[LineNumberP]; - Lines[LineNumberP].Line[Lines[LineNumberP].High].LyricWidth := glTextWidth(Lines[LineNumberP].Line[Lines[LineNumberP].High].Lyric); - - //Total Notes Patch - Lines[LineNumberP].Line[Lines[LineNumberP].High].TotalNotes := 0; - for I := low(Lines[LineNumberP].Line[Lines[LineNumberP].High].Note) to high(Lines[LineNumberP].Line[Lines[LineNumberP].High].Note) do - begin - if (Lines[LineNumberP].Line[Lines[LineNumberP].High].Note[I].NoteType = ntGolden) then - Lines[LineNumberP].Line[Lines[LineNumberP].High].TotalNotes := Lines[LineNumberP].Line[Lines[LineNumberP].High].TotalNotes + Lines[LineNumberP].Line[Lines[LineNumberP].High].Note[I].Length; - - if (Lines[LineNumberP].Line[Lines[LineNumberP].High].Note[I].NoteType <> ntFreestyle) then - Lines[LineNumberP].Line[Lines[LineNumberP].High].TotalNotes := Lines[LineNumberP].Line[Lines[LineNumberP].High].TotalNotes + Lines[LineNumberP].Line[Lines[LineNumberP].High].Note[I].Length; - end; - //Total Notes Patch End - - - // nowa czesc //Neuer Satz //Update New Part + if (Lines[LineNumberP].Line[Lines[LineNumberP].High].HighNote <> -1) then + begin //create a new line SetLength(Lines[LineNumberP].Line, Lines[LineNumberP].Number + 1); - Lines[LineNumberP].High := Lines[LineNumberP].High + 1; - Lines[LineNumberP].Number := Lines[LineNumberP].Number + 1; + Inc(Lines[LineNumberP].High); + Inc(Lines[LineNumberP].Number); end else - begin //Use old Sentence if it has no notes + begin //use old line if it there were no notes added since last call of NewSentence Log.LogError('Error loading Song, sentence w/o note found in line ' + InttoStr(FileLineNo) + ': ' + Filename); end; Lines[LineNumberP].Line[Lines[LineNumberP].High].HighNote := -1; + //set the current lines value to zero + //it will be incremented w/ the value of every added note + Lines[LineNumberP].Line[Lines[LineNumberP].High].TotalNotes := 0; + + //basenote is the pitch of the deepest note, it is used for note drawing. + //if a note with a less value than the current sentences basenote is found, + //basenote will be set to this notes pitch. Therefore the initial value of + //this field has to be very high. + Lines[LineNumberP].Line[Lines[LineNumberP].High].BaseNote := High(Integer); + + if self.Relative then begin Lines[LineNumberP].Line[Lines[LineNumberP].High].Start := Param1; @@ -1081,9 +1062,7 @@ begin else Lines[LineNumberP].Line[Lines[LineNumberP].High].Start := Param1; - Lines[LineNumberP].Line[Lines[LineNumberP].High].LastLine := False; - - Base[LineNumberP] := 100; // high number + Lines[LineNumberP].Line[Lines[LineNumberP].High].LastLine := false; end; procedure TSong.clear(); @@ -1122,13 +1101,13 @@ begin Resolution := 4; Creator := ''; + Relative := false; end; - function TSong.Analyse(): boolean; begin - Result := False; + Result := false; //Reset LineNo FileLineNo := 0; @@ -1155,7 +1134,7 @@ end; function TSong.AnalyseXML(): boolean; begin - Result := False; + Result := false; //Reset LineNo FileLineNo := 0; diff --git a/unicode/src/base/USongs.pas b/unicode/src/base/USongs.pas index ac67eed0..852ccfc4 100644 --- a/unicode/src/base/USongs.pas +++ b/unicode/src/base/USongs.pas @@ -158,11 +158,13 @@ implementation uses StrUtils, - UGraphic, UCovers, UFiles, + UGraphic, UMain, UIni, + UPath, + UNote, UUnicodeUtils; constructor TSongs.Create(); @@ -282,7 +284,11 @@ var lSong : TSong; begin - Files := Platform.DirectoryFindFiles( Dir, '.txt', true); + try + Files := Platform.DirectoryFindFiles( Dir, '.txt', true) + except + Log.LogError('Couldn''t deal with directory/file: ' + Dir + ' in TSongs.BrowseTXTFiles') + end; for i := 0 to Length(Files)-1 do begin @@ -315,7 +321,11 @@ var lSong : TSong; begin - Files := Platform.DirectoryFindFiles( Dir, '.xml', true); + try + Files := Platform.DirectoryFindFiles( Dir, '.xml', true) + except + Log.LogError('Couldn''t deal with directory/file: ' + Dir + ' in TSongs.BrowseXMLFiles') + end; for i := 0 to Length(Files)-1 do begin @@ -670,7 +680,7 @@ begin end; // set CatNumber of last category - if (Ini.Tabs_at_startup = 1) and (High(Song) >= 1) then + if (Ini.TabsAtStartup = 1) and (High(Song) >= 1) then begin // set number of songs in previous category SongIndex := CatIndex - CatNumber; diff --git a/unicode/src/base/UTexture.pas b/unicode/src/base/UTexture.pas index 4f33b78a..962bd2b0 100644 --- a/unicode/src/base/UTexture.pas +++ b/unicode/src/base/UTexture.pas @@ -93,7 +93,7 @@ type TTextureEntry = record Name: string; Typ: TTextureType; - Color: Cardinal; + Color: cardinal; // we use normal TTexture, it's easier to implement and if needed - we copy ready data Texture: TTexture; // Full-size texture @@ -104,8 +104,8 @@ type private Texture: array of TTextureEntry; public - procedure AddTexture(var Tex: TTexture; Typ: TTextureType; Color: Cardinal; Cache: boolean); - function FindTexture(const Name: string; Typ: TTextureType; Color: Cardinal): integer; + procedure AddTexture(var Tex: TTexture; Typ: TTextureType; Color: cardinal; Cache: boolean); + function FindTexture(const Name: string; Typ: TTextureType; Color: cardinal): integer; end; TTextureUnit = class @@ -115,7 +115,7 @@ type Limit: integer; procedure AddTexture(var Tex: TTexture; Typ: TTextureType; Cache: boolean = false); overload; - procedure AddTexture(var Tex: TTexture; Typ: TTextureType; Color: Cardinal; Cache: boolean = false); overload; + procedure AddTexture(var Tex: TTexture; Typ: TTextureType; Color: cardinal; Cache: boolean = false); overload; function GetTexture(const Name: string; Typ: TTextureType; FromCache: boolean = false): TTexture; overload; function GetTexture(const Name: string; Typ: TTextureType; Col: LongWord; FromCache: boolean = false): TTexture; overload; function LoadTexture(FromRegistry: boolean; const Identifier: string; Typ: TTextureType; Col: LongWord): TTexture; overload; @@ -123,7 +123,7 @@ type function LoadTexture(const Identifier: string): TTexture; overload; function CreateTexture(Data: PChar; const Name: string; Width, Height: word; BitsPerPixel: byte): TTexture; procedure UnloadTexture(const Name: string; Typ: TTextureType; FromCache: boolean); overload; - procedure UnloadTexture(const Name: string; Typ: TTextureType; Col: Cardinal; FromCache: boolean); overload; + procedure UnloadTexture(const Name: string; Typ: TTextureType; Col: cardinal; FromCache: boolean); overload; //procedure FlushTextureDatabase(); constructor Create; @@ -164,10 +164,10 @@ begin SDL_FreeSurface(TempSurface); end; end; - + { TTextureDatabase } -procedure TTextureDatabase.AddTexture(var Tex: TTexture; Typ: TTextureType; Color: Cardinal; Cache: boolean); +procedure TTextureDatabase.AddTexture(var Tex: TTexture; Typ: TTextureType; Color: cardinal; Cache: boolean); var TextureIndex: integer; begin @@ -188,7 +188,7 @@ begin Texture[TextureIndex].Texture := Tex; end; -function TTextureDatabase.FindTexture(const Name: string; Typ: TTextureType; Color: Cardinal): integer; +function TTextureDatabase.FindTexture(const Name: string; Typ: TTextureType; Color: cardinal): integer; var TextureIndex: integer; CurrentTexture: PTextureEntry; @@ -211,7 +211,6 @@ begin end; end; - { TTextureUnit } constructor TTextureUnit.Create; @@ -226,13 +225,12 @@ begin inherited Destroy; end; - procedure TTextureUnit.AddTexture(var Tex: TTexture; Typ: TTextureType; Cache: boolean); begin TextureDatabase.AddTexture(Tex, Typ, 0, Cache); end; -procedure TTextureUnit.AddTexture(var Tex: TTexture; Typ: TTextureType; Color: Cardinal; Cache: boolean); +procedure TTextureUnit.AddTexture(var Tex: TTexture; Typ: TTextureType; Color: cardinal; Cache: boolean); begin TextureDatabase.AddTexture(Tex, Typ, Color, Cache); end; @@ -251,8 +249,8 @@ end; function TTextureUnit.LoadTexture(const Identifier: string; Typ: TTextureType; Col: LongWord): TTexture; var TexSurface: PSDL_Surface; - newWidth, newHeight: Cardinal; - oldWidth, oldHeight: Cardinal; + newWidth, newHeight: integer; + oldWidth, oldHeight: integer; ActTex: GLuint; begin // zero texture data @@ -431,8 +429,8 @@ begin {$ELSE} glTexImage2D(GL_TEXTURE_2D, 0, 3, Width, Height, 0, GL_RGB, GL_UNSIGNED_BYTE, Data); {$ENDIF} - - { + +{ if Mipmapping then begin Error := gluBuild2DMipmaps(GL_TEXTURE_2D, 3, W, H, GL_RGB, GL_UNSIGNED_BYTE, @Data[0]); @@ -440,8 +438,8 @@ begin if Error > 0 then Log.LogError('gluBuild2DMipmaps() failed', 'TTextureUnit.CreateTexture'); end; - } - +} + Result.X := 0; Result.Y := 0; Result.Z := 0; @@ -474,14 +472,14 @@ begin UnloadTexture(Name, Typ, 0, FromCache); end; -procedure TTextureUnit.UnloadTexture(const Name: string; Typ: TTextureType; Col: Cardinal; FromCache: boolean); +procedure TTextureUnit.UnloadTexture(const Name: string; Typ: TTextureType; Col: cardinal; FromCache: boolean); var T: integer; TexNum: GLuint; begin T := TextureDatabase.FindTexture(Name, Typ, Col); - if not FromCache then + if not FromCache then begin TexNum := TextureDatabase.Texture[T].Texture.TexNum; if TexNum > 0 then @@ -529,20 +527,20 @@ end; function ParseTextureType(const TypeStr: string; Default: TTextureType): TTextureType; var - TexType: TTextureType; + TextureType: TTextureType; UpCaseStr: string; begin UpCaseStr := UpperCase(TypeStr); - for TexType := Low(TextureTypeStr) to High(TextureTypeStr) do + for TextureType := Low(TextureTypeStr) to High(TextureTypeStr) do begin - if (UpCaseStr = UpperCase(TextureTypeStr[TexType])) then + if (UpCaseStr = UpperCase(TextureTypeStr[TextureType])) then begin - Result := TexType; + Result := TextureType; Exit; end; end; - Log.LogWarn('Unknown texture-type: "' + TypeStr + '"', 'ParseTextureType'); - Result := TEXTURE_TYPE_PLAIN; + Log.LogWarn('Unknown texture type: "' + TypeStr + '". Using default texture type "' + TextureTypeToStr(Default) + '"', 'ParseTextureType'); + Result := Default; end; end. diff --git a/unicode/src/base/UThemes.pas b/unicode/src/base/UThemes.pas index 361ed87d..9bf858ed 100644 --- a/unicode/src/base/UThemes.pas +++ b/unicode/src/base/UThemes.pas @@ -484,6 +484,16 @@ type ButtonExit: TThemeButton; end; + TThemeEdit = class(TThemeBasic) + ButtonConvert: TThemeButton; + ButtonExit: TThemeButton; + + TextDescription: TThemeText; + TextDescriptionLong: TThemeText; + Description: array[0..5] of string; + DescriptionLong: array[0..5] of string; + end; + //Error- and Check-Popup TThemeError = class(TThemeBasic) Button1: TThemeButton; @@ -723,6 +733,8 @@ type OptionsThemes: TThemeOptionsThemes; OptionsRecord: TThemeOptionsRecord; OptionsAdvanced: TThemeOptionsAdvanced; + //edit + Edit: TThemeEdit; //error and check popup ErrorPopup: TThemeError; CheckPopup: TThemeCheck; @@ -852,6 +864,8 @@ begin OptionsRecord := TThemeOptionsRecord.Create; OptionsAdvanced := TThemeOptionsAdvanced.Create; + Edit := TThemeEdit.Create; + ErrorPopup := TThemeError.Create; CheckPopup := TThemeCheck.Create; @@ -1246,6 +1260,18 @@ begin ThemeLoadSelectSlide(OptionsAdvanced.SelectPartyPopup, 'OptionsAdvancedSelectPartyPopup'); ThemeLoadButton (OptionsAdvanced.ButtonExit, 'OptionsAdvancedButtonExit'); + //Edit Menu + ThemeLoadBasic (Edit, 'Edit'); + + ThemeLoadButton(Edit.ButtonConvert, 'EditButtonConvert'); + ThemeLoadButton(Edit.ButtonExit, 'EditButtonExit'); + + Edit.Description[0] := Language.Translate('SING_EDIT_BUTTON_DESCRIPTION_CONVERT'); + Edit.Description[1] := Language.Translate('SING_EDIT_BUTTON_DESCRIPTION_EXIT'); + + ThemeLoadText(Edit.TextDescription, 'EditTextDescription'); + Edit.TextDescription.Text := Edit.Description[0]; + //error and check popup ThemeLoadBasic (ErrorPopup, 'ErrorPopup'); ThemeLoadButton(ErrorPopup.Button1, 'ErrorPopupButton1'); @@ -2310,6 +2336,9 @@ begin freeandnil(OptionsAdvanced); OptionsAdvanced := TThemeOptionsAdvanced.Create; + freeandnil(Edit); + Edit := TThemeEdit.Create; + freeandnil(ErrorPopup); ErrorPopup := TThemeError.Create; |