DEADSOFTWARE

gl: implement load screen
authorDeaDDooMER <deaddoomer@deadsoftware.ru>
Wed, 27 Jul 2022 18:53:19 +0000 (21:53 +0300)
committerDeaDDooMER <deaddoomer@deadsoftware.ru>
Fri, 9 Jun 2023 09:06:59 +0000 (12:06 +0300)
17 files changed:
src/game/Doom2DF.lpr
src/game/g_game.pas
src/game/g_items.pas
src/game/g_map.pas
src/game/g_monsters.pas
src/game/g_netmsg.pas
src/game/g_res_downloader.pas
src/game/g_saveload.pas
src/game/g_weapons.pas
src/game/g_window.pas
src/game/renders/opengl/r_common.pas
src/game/renders/opengl/r_console.pas
src/game/renders/opengl/r_draw.pas
src/game/renders/opengl/r_gui.pas
src/game/renders/opengl/r_loadscreen.pas [new file with mode: 0644]
src/game/renders/opengl/r_map.pas
src/game/renders/opengl/r_render.pas

index 1e358b9224d6d6a94f33242dc3fca5cbd417fccb..51d0cb9617414851a7056e02e85ddeca90aa284e 100644 (file)
@@ -206,6 +206,7 @@ uses
     r_common in 'renders/opengl/r_common.pas',
     r_console in 'renders/opengl/r_console.pas',
     r_gui in 'renders/opengl/r_gui.pas',
+    r_loadscreen in 'renders/opengl/r_loadscreen.pas',
   {$ELSE}
     {$FATAL render driver not selected}
   {$ENDIF}
@@ -1011,6 +1012,26 @@ end;
     {$ENDIF}
   end;
 
+  procedure ProcessLoading;
+    var update: Boolean;
+  begin
+    {$IFDEF ENABLE_SYSTEM}
+      update := sys_HandleInput() = False;
+    {$ELSE}
+      update := True;
+    {$ENDIF}
+    if update then
+    begin
+      e_SoundUpdate;
+      // TODO: At the moment, I left here only host network processing, because the client code must
+      // handle network events on its own. Otherwise separate network cases that use different calls to
+      // enet_host_service() WILL lose their packets (for example, resource downloading). So they have
+      // to handle everything by themselves. But in general, this MUST be removed completely, since
+      // updating the window should never affect the network. Use single enet_host_service(), period.
+      if NetMode = NET_SERVER then g_Net_Host_Update();
+    end
+  end;
+
   procedure Startup;
   begin
     Randomize;
@@ -1035,6 +1056,11 @@ end;
     DebugOptions;
     g_Net_InitLowLevel;
     // TODO init serverlist
+    {$IFDEF ENABLE_RENDER}
+      r_Render_SetProcessLoadingCallback(@ProcessLoading);
+    {$ENDIF}
+    g_Game_SetLoadingText(Format('Doom 2D: Forever %s', [GAME_VERSION]), 0, False);
+    g_Game_SetLoadingText('', 0, False);
     {$IFDEF ENABLE_HOLMES}
       InitHolmes;
     {$ENDIF}
@@ -1057,6 +1083,9 @@ end;
     {$ENDIF}
     Time_Old := GetTickCount64();
     while not ProcessMessage() do begin end;
+    {$IFDEF ENABLE_RENDER}
+      r_Render_SetProcessLoadingCallback(nil);
+    {$ENDIF}
     g_Console_WriteGameConfig;
     {$IFDEF ENABLE_MENU}
       g_GUI_Destroy;
index ce8c5787d770a68a1ca9adcf66b60b62931abb18..380126ee18a6a1d6ea60a876883518ce6dd53106 100644 (file)
@@ -146,9 +146,6 @@ procedure GameCommands(P: SSArray);
 procedure GameCheats(P: SSArray);
 procedure DebugCommands(P: SSArray);
 procedure g_Game_Process_Params;
-procedure g_Game_SetLoadingText(Text: String; Max: Integer; reWrite: Boolean);
-procedure g_Game_StepLoading(Value: Integer = -1);
-procedure g_Game_ClearLoading();
 procedure g_Game_SetDebugMode();
 
 function IsActivePlayer(p: TPlayer): Boolean;
@@ -170,9 +167,6 @@ procedure SortGameStat(var stat: TPlayerStatArray);
 const
   GAME_TICK = 28;
 
-  LOADING_SHOW_STEP = 100;
-  LOADING_INTERLINE = 20;
-
   GT_NONE   = 0;
   GT_SINGLE = 1;
   GT_CUSTOM = 2;
@@ -416,15 +410,6 @@ function gPause (): Boolean; inline;
       TotalSecrets: Integer;
     end;
 
-    TLoadingStat = record
-      CurValue: Integer;
-      MaxValue: Integer;
-      ShowCount: Integer;
-      Msgs: Array of String;
-      NextMsg: Word;
-      PBarWasHere: Boolean; // did we draw a progress bar for this message?
-    end;
-
     TDynLight = record
       x, y, radius: Integer;
       r, g, b, a: Single;
@@ -437,7 +422,6 @@ function gPause (): Boolean; inline;
     StatShotDone: Boolean;
     StatFilename: string = ''; // used by stat screenshot to save with the same name as the csv
     SingleStat: TEndSingleGameStat;
-    LoadingStat: TLoadingStat;
     MessageText: String;
     IsDrawStat: Boolean;
     EndingGameCounter: Byte;
@@ -1454,12 +1438,6 @@ begin
   sfsGCDisable(); // temporary disable removing of temporary volumes
 
   try
-    g_Game_ClearLoading();
-    g_Game_SetLoadingText(Format('Doom 2D: Forever %s', [GAME_VERSION]), 0, False);
-    g_Game_SetLoadingText('', 0, False);
-
-//    g_Game_SetLoadingText(_lc[I_LOAD_MODELS], 0, False);
-
     gGameOn := false;
     gPauseMain := false;
     gPauseHolmes := false;
@@ -1467,7 +1445,6 @@ begin
 
     {e_MouseInfo.Accel := 1.0;}
 
-    g_Game_SetLoadingText(_lc[I_LOAD_GAME_DATA], 0, False);
     g_Game_LoadData();
 
     g_Game_SetLoadingText(_lc[I_LOAD_MUSIC], 0, False);
@@ -2568,6 +2545,7 @@ begin
   if DataLoaded then Exit;
 
   e_WriteLog('Loading game data...', TMsgType.Notify);
+  g_Game_SetLoadingText(_lc[I_LOAD_GAME_DATA], 0, False);
 
   g_Sound_CreateWADEx('SOUND_GAME_TELEPORT', GameWAD+':SOUNDS\TELEPORT');
   g_Sound_CreateWADEx('SOUND_GAME_NOTELEPORT', GameWAD+':SOUNDS\NOTELEPORT');
@@ -2650,10 +2628,8 @@ begin
 
   g_Game_LoadChatSounds(GameWAD+':CHATSND\SNDCFG');
 
-  g_Game_SetLoadingText(_lc[I_LOAD_ITEMS_DATA], 0, False);
   g_Items_LoadData();
 
-  g_Game_SetLoadingText(_lc[I_LOAD_WEAPONS_DATA], 0, False);
   g_Weapon_LoadData();
 
   g_Monsters_LoadData();
@@ -6812,81 +6788,6 @@ begin
   gCheats := True;
 end;
 
-procedure g_Game_SetLoadingText(Text: String; Max: Integer; reWrite: Boolean);
-var
-  i: Word;
-begin
-  if Length(LoadingStat.Msgs) = 0 then
-    Exit;
-
-  with LoadingStat do
-  begin
-    if not reWrite then
-    begin // Переходим на следующую строку или скроллируем:
-      if NextMsg = Length(Msgs) then
-        begin // scroll
-          for i := 0 to High(Msgs)-1 do
-            Msgs[i] := Msgs[i+1];
-        end
-      else
-        Inc(NextMsg);
-    end else
-      if NextMsg = 0 then
-        Inc(NextMsg);
-
-    Msgs[NextMsg-1] := Text;
-    CurValue := 0;
-    MaxValue := Max;
-    ShowCount := 0;
-    PBarWasHere := false;
-  end;
-
-  {$IFDEF ENABLE_MENU}
-    g_ActiveWindow := nil;
-  {$ENDIF}
-
-  ProcessLoading(true);
-end;
-
-procedure g_Game_StepLoading(Value: Integer = -1);
-begin
-  with LoadingStat do
-  begin
-    if Value = -1 then
-    begin
-      Inc(CurValue);
-      Inc(ShowCount);
-    end
-    else
-      CurValue := Value;
-
-    if (ShowCount > LOADING_SHOW_STEP) or (Value > -1) then
-    begin
-      ShowCount := 0;
-      ProcessLoading(False);
-    end;
-  end;
-end;
-
-procedure g_Game_ClearLoading();
-var
-  len: Word;
-begin
-  with LoadingStat do
-  begin
-    CurValue := 0;
-    MaxValue := 0;
-    ShowCount := 0;
-    len := ((gScreenHeight div 3)*2 - 50) div LOADING_INTERLINE;
-    if len < 1 then len := 1;
-    SetLength(Msgs, len);
-    for len := Low(Msgs) to High(Msgs) do
-      Msgs[len] := '';
-    NextMsg := 0;
-    PBarWasHere := false;
-  end;
-end;
-
 procedure Parse_Params(var pars: TParamStrValues);
 var
   i: Integer;
index 5a43c83a1efff4f12049d34e8a08a1328740f537..8f369bb61926fe6247ee2c9c1923c334042110d2 100644 (file)
@@ -97,7 +97,7 @@ implementation
     Math,
     g_basic, g_sound, g_map,
     g_game, g_triggers, g_console, g_player, g_net, g_netmsg,
-    e_log, g_options,
+    e_log, g_options, g_language, g_window,
     g_grid, binheap, idpool, utils, xstreams
   ;
 
@@ -203,6 +203,7 @@ const
 procedure g_Items_LoadData();
 begin
   e_WriteLog('Loading items data...', TMsgType.Notify);
+  g_Game_SetLoadingText(_lc[I_LOAD_ITEMS_DATA], 0, False);
 
   g_Sound_CreateWADEx('SOUND_ITEM_RESPAWNITEM', GameWAD+':SOUNDS\RESPAWNITEM');
   g_Sound_CreateWADEx('SOUND_ITEM_GETRULEZ', GameWAD+':SOUNDS\GETRULEZ');
index 85bffa627423e79bb74a14354eb8464edd4ac714..71f50d1c66c93f4af8352dfe44e400b2ec506005 100644 (file)
@@ -243,7 +243,7 @@ implementation
     {$ENDIF}
     e_input, e_log, e_res, g_items, g_console,
     g_weapons, g_game, g_sound, e_sound, CONFIG,
-    g_options, g_triggers, g_player,
+    g_options, g_triggers, g_player, g_window,
     Math, g_monsters, g_saveload, g_language, g_netmsg,
     sfs, xstreams, hashtable, wadreader,
     g_res_downloader
index db552adb8122da64e4441c52811555460bded0b1..5fa50114660f43d7a5df764ce662a16ab4b11b0f 100644 (file)
@@ -542,7 +542,7 @@ uses
     g_corpses,
   {$ENDIF}
   e_log, g_sound, g_player, g_game,
-  g_weapons, g_triggers, g_items, g_options,
+  g_weapons, g_triggers, g_items, g_options, g_window,
   g_console, g_map, Math, wadreader,
   g_language, g_netmsg, idpool, utils, xstreams;
 
@@ -896,10 +896,6 @@ end;
 procedure g_Monsters_LoadData();
 begin
   e_WriteLog('Loading monsters data...', TMsgType.Notify);
-
-  g_Game_SetLoadingText(_lc[I_LOAD_MONSTER_TEXTURES], 133, False);
-  g_Game_StepLoading(133);
-
   g_Game_SetLoadingText(_lc[I_LOAD_MONSTER_SOUNDS], 0, False);
 
   g_Sound_CreateWADEx('SOUND_MONSTER_BARREL_DIE', GameWAD+':MSOUNDS\BARREL_DIE');
index 4ada39477e8bf9ee37c7a738029786fce98211a4..2652bc504353f4e057043d14897383c45be50a0b 100644 (file)
@@ -300,7 +300,7 @@ implementation
       g_corpses,
     {$ENDIF}
     Math, ENet, e_input, e_log, g_base, g_basic,
-    g_sound, g_console, g_options,
+    g_sound, g_console, g_options, g_window,
     g_game, g_player, g_map, g_panel, g_items, g_weapons, g_phys,
     g_language, g_monsters, g_netmaster, utils, wadreader, MAPDEF
   ;
index 663d62baf8fecb864cb0a82b81da3b746659f1b6..80f2ec7a04a46967c2ee682b559591d50e3dbe05 100644 (file)
@@ -35,7 +35,7 @@ procedure g_Res_CreateDatabases (allowRescan: Boolean=false);
 
 implementation
 
-uses g_language, sfs, utils, wadreader, g_game, hashtable, fhashdb, e_res, g_options;
+uses g_language, sfs, utils, wadreader, g_game, hashtable, fhashdb, e_res, g_options, g_window;
 
 var
   // cvars
index f513f3af436b32fa27482cd5ab9eb6d00e783c36..f17f34db93aba9e62c40da03e29e808f98fd7029 100644 (file)
@@ -45,7 +45,7 @@ uses
   MAPDEF, utils, xstreams,
   g_game, g_items, g_map, g_monsters, g_triggers,
   g_basic, Math, wadreader,
-  g_weapons, g_player, g_console,
+  g_weapons, g_player, g_console, g_window,
   e_log, e_res, g_language, g_options;
 
 const
index 8fdde869c0bcda1b9a175a3805bc0c2bc528be53..96c46c8d4fc0cad7a2d0e36eeaf88b431addbaf9 100644 (file)
@@ -124,7 +124,7 @@ implementation
     Math, g_map, g_player, g_sound, g_panel,
     g_console, g_options, g_game,
     g_triggers, MAPDEF, e_log, g_monsters, g_saveload,
-    g_language, g_netmsg, g_grid,
+    g_language, g_netmsg, g_grid, g_window,
     geom, binheap, hashtable, utils, xstreams
   ;
 
@@ -1112,6 +1112,7 @@ end;
 procedure g_Weapon_LoadData();
 begin
   e_WriteLog('Loading weapons data...', TMsgType.Notify);
+  g_Game_SetLoadingText(_lc[I_LOAD_WEAPONS_DATA], 0, False);
 
   g_Sound_CreateWADEx('SOUND_WEAPON_HITPUNCH', GameWAD+':SOUNDS\HITPUNCH');
   g_Sound_CreateWADEx('SOUND_WEAPON_MISSPUNCH', GameWAD+':SOUNDS\MISSPUNCH');
index 2b20517baa9466c43bc29df4d79a2d95326665d8..92ee3b97161f475f88d1b9acf04528fa566c813d 100644 (file)
@@ -17,6 +17,10 @@ unit g_window;
 
 interface
 
+  procedure g_Game_ClearLoading;
+  procedure g_Game_SetLoadingText (const text: String; maxval: Integer; rewrite: Boolean);
+  procedure g_Game_StepLoading (value: Integer = -1);
+
   procedure ProcessLoading (forceUpdate: Boolean=false);
 
 implementation
@@ -32,26 +36,33 @@ implementation
   ;
 
   procedure ProcessLoading (forceUpdate: Boolean = False);
-    var update: Boolean;
   begin
-    {$IFDEF ENABLE_SYSTEM}
-      update := sys_HandleInput() = False;
-    {$ELSE}
-      update := True;
+    {$IFDEF ENABLE_RENDER}
+      r_Render_DrawLoading(forceUpdate);
+    {$ENDIF}
+  end;
+
+  procedure g_Game_ClearLoading;
+  begin
+    {$IFDEF ENABLE_RENDER}
+      r_Render_ClearLoading;
+    {$ENDIF}
+  end;
+
+  procedure g_Game_SetLoadingText (const text: String; maxval: Integer; rewrite: Boolean);
+  begin
+    {$IFDEF ENABLE_RENDER}
+      if maxval < 0 then maxval := 0;
+      r_Render_SetLoading(text, maxval);
+    {$ENDIF}
+  end;
+
+  procedure g_Game_StepLoading (value: Integer = -1);
+  begin
+    {$IFDEF ENABLE_RENDER}
+      if value < 0 then value := 1;
+      r_Render_StepLoading(value);
     {$ENDIF}
-    if update then
-    begin
-      {$IFDEF ENABLE_RENDER}
-        r_Render_DrawLoading(forceUpdate);
-      {$ENDIF}
-      e_SoundUpdate();
-      // TODO: At the moment, I left here only host network processing, because the client code must
-      // handle network events on its own. Otherwise separate network cases that use different calls to
-      // enet_host_service() WILL lose their packets (for example, resource downloading). So they have
-      // to handle everything by themselves. But in general, this MUST be removed completely, since
-      // updating the window should never affect the network. Use single enet_host_service(), period.
-      if NetMode = NET_SERVER then g_Net_Host_Update();
-    end
   end;
 
 end.
index 99f46d1468c3ef3e5a2d39897178b750b9e2c48c..9c6b8b420ff0052207db872a45f3dae8b494dbbb 100644 (file)
@@ -17,7 +17,7 @@ unit r_common;
 
 interface
 
-  uses r_textures, g_player, g_phys;
+  uses r_textures, r_fonts, g_player, g_phys;
 
   type
     TBasePoint = (
@@ -36,6 +36,9 @@ interface
     smallfont: TGLFont;
     menufont: TGLFont;
 
+  var
+    r_Common_ProcessLoadingCallback: TProcedure;
+
   function  r_Common_LoadThis (const name: AnsiString; var here: THereTexture): Boolean;
   procedure r_Common_FreeThis (var here: THereTexture);
 
@@ -54,6 +57,21 @@ interface
   procedure r_Common_GetCameraPos (const p: TPlayer; center: Boolean; out x, y: Integer);
   function  r_Common_GetPosByUID (uid: WORD; out obj: TObj; out x, y: Integer): Boolean;
 
+  procedure r_Common_DrawBackgroundImage (img: TGLTexture);
+  procedure r_Common_DrawBackground (const name: AnsiString);
+
+  procedure r_Common_ClearLoading;
+  procedure r_Common_SetLoading (const text: String; maxval: Integer);
+  procedure r_Common_StepLoading (incval: Integer);
+  procedure r_Common_DrawLoading (force: Boolean);
+
+  function r_Common_LoadTextureFromFile (const filename: AnsiString; log: Boolean = True): TGLTexture;
+  function r_Common_LoadTextureMultiFromFile (const filename: AnsiString; log: Boolean = True): TGLMultiTexture;
+  function r_Common_LoadTextureMultiFromFileAndInfo (const filename: AnsiString; w, h, count: Integer; log: Boolean = True): TGLMultiTexture;
+  function r_Common_LoadTextureMultiTextFromFile (const filename: AnsiString; var txt: TAnimTextInfo; log: Boolean = True): TGLMultiTexture;
+  function r_Common_LoadTextureStreamFromFile (const filename: AnsiString; w, h, count, cw: Integer; st: TGLTextureArray; rs: TRectArray; log: Boolean = True): Boolean;
+  function r_Common_LoadTextureFontFromFile (const filename: AnsiString; constref f: TFontInfo; skipch: Integer; log: Boolean = true): TGLFont;
+
   procedure r_Common_Load;
   procedure r_Common_Free;
 
@@ -66,9 +84,12 @@ implementation
     {$IFDEF ENABLE_CORPSES}
       g_corpses,
     {$ENDIF}
-    r_draw, r_fonts
+    r_draw, r_loadscreen
   ;
 
+  var
+    BackgroundTexture: THereTexture;
+
   procedure r_Common_GetObjectPos (const obj: TObj; out x, y: Integer);
     var fx, fy: Integer;
   begin
@@ -310,29 +331,118 @@ implementation
     end;
   end;
 
+  procedure r_Common_DrawBackgroundImage (img: TGLTexture);
+    var fw, w, h: LongInt;
+  begin
+    if img <> nil then
+    begin
+      img := BackgroundTexture.id;
+      if img.width = img.height then fw := img.width * 4 div 3 else fw := img.width; // fix aspect 4:3
+      r_Common_CalcAspect(fw, img.height, gScreenWidth, gScreenHeight, false, w, h);
+      r_Draw_Texture(img, gScreenWidth div 2 - w div 2, 0, w, h, false, 255, 255, 255, 255, false);
+    end
+  end;
+
+  procedure r_Common_DrawBackground (const name: AnsiString);
+  begin
+    if r_Common_LoadThis(name, BackgroundTexture) then
+      r_Common_DrawBackgroundImage(BackgroundTexture.id)
+  end;
+
   function r_Common_LoadFont (const name: AnsiString): TGLFont;
     var info: TFontInfo; skiphack: Integer;
   begin
     result := nil;
     if name = 'STD' then skiphack := 144 else skiphack := 0;
     if r_Font_LoadInfoFromFile(GameWad + ':FONTS/' + name + 'TXT', info) then
-      result := r_Textures_LoadFontFromFile(GameWad + ':FONTS/' + name + 'FONT', info, skiphack, true);
+      result := r_Common_LoadTextureFontFromFile(GameWad + ':FONTS/' + name + 'FONT', info, skiphack, true);
     if result = nil then
       e_logwritefln('failed to load font %s', [name]);
   end;
 
   procedure r_Common_Load;
   begin
-    stdfont := r_Common_LoadFont('STD');
-    smallfont := r_Common_LoadFont('SMALL');
+    r_Common_SetLoading('Fonts', 3);
     menufont := r_Common_LoadFont('MENU');
+    smallfont := r_Common_LoadFont('SMALL');
+    stdfont := r_Common_LoadFont('STD');
+    BackgroundTexture := DEFAULT(THereTexture);
   end;
 
   procedure r_Common_Free;
   begin
+    r_Common_FreeThis(BackgroundTexture);
     menufont.Free;
     smallfont.Free;
     stdfont.Free;
   end;
 
+  (* --------- Loading screen helpers --------- *)
+
+  procedure r_Common_ProcessLoading;
+  begin
+    if @r_Common_ProcessLoadingCallback <> nil then
+      r_Common_ProcessLoadingCallback;
+  end;
+
+  procedure r_Common_DrawLoading (force: Boolean);
+  begin
+    r_LoadScreen_Draw(force);
+    r_Common_ProcessLoading;
+  end;
+
+  procedure r_Common_ClearLoading;
+  begin
+    r_LoadScreen_Clear;
+    r_Common_DrawLoading(true);
+  end;
+
+  procedure r_Common_SetLoading (const text: String; maxval: Integer);
+  begin
+    r_LoadScreen_Set(text, maxval);
+    r_Common_DrawLoading(true);
+  end;
+
+  procedure r_Common_StepLoading (incval: Integer);
+  begin
+    r_LoadScreen_Step(incval);
+    r_Common_DrawLoading(false);
+  end;
+
+  function r_Common_LoadTextureFromFile (const filename: AnsiString; log: Boolean = True): TGLTexture;
+  begin
+    result := r_Textures_LoadFromFile(filename, log);
+    r_Common_StepLoading(1);
+  end;
+
+  function r_Common_LoadTextureMultiFromFile (const filename: AnsiString; log: Boolean = True): TGLMultiTexture;
+  begin
+    result := r_Textures_LoadMultiFromFile(filename, log);
+    r_Common_StepLoading(1);
+  end;
+
+  function r_Common_LoadTextureMultiFromFileAndInfo (const filename: AnsiString; w, h, count: Integer; log: Boolean = True): TGLMultiTexture;
+  begin
+    result := r_Textures_LoadMultiFromFileAndInfo(filename, w, h, count, log);
+    r_Common_StepLoading(1);
+  end;
+
+  function r_Common_LoadTextureMultiTextFromFile (const filename: AnsiString; var txt: TAnimTextInfo; log: Boolean = True): TGLMultiTexture;
+  begin
+    result := r_Textures_LoadMultiTextFromFile(filename, txt, log);
+    r_Common_StepLoading(1);
+  end;
+
+  function r_Common_LoadTextureStreamFromFile (const filename: AnsiString; w, h, count, cw: Integer; st: TGLTextureArray; rs: TRectArray; log: Boolean = True): Boolean;
+  begin
+    r_Textures_LoadStreamFromFile(filename, w, h, count, cw, st, rs, log);
+    r_Common_StepLoading(1);
+  end;
+
+  function r_Common_LoadTextureFontFromFile (const filename: AnsiString; constref f: TFontInfo; skipch: Integer; log: Boolean = true): TGLFont;
+  begin
+    result := r_Textures_LoadFontFromFile (filename, f, skipch, log);
+    r_Common_StepLoading(1);
+  end;
+
 end.
index 60b14c1f6b12c38b485691b6dc483d51a4e646d3..4487afbf4c059a164e478e205ba2508c97a34597 100644 (file)
@@ -30,7 +30,7 @@ implementation
 
   uses
     Math, utils, conbuf,
-    g_game, g_options, g_console,
+    g_game, g_options, g_console, g_language,
     r_draw, r_textures, r_fonts, r_common
   ;
 
@@ -56,6 +56,7 @@ implementation
 
   procedure r_Console_Load;
   begin
+    r_Common_SetLoading(_lc[I_LOAD_CONSOLE], 1);
     Background := r_Textures_LoadFromFile(GameWad + ':TEXTURES/CONSOLE');
   end;
 
index 1a6b573db136ff35341a7046f1d73d4471fcd74d..55d9dad6432db0bc2d1832aa6a3fc8af3fee831c 100644 (file)
@@ -76,7 +76,8 @@ implementation
     glOrtho(0, w, h, 0, 0, 1);
     glMatrixMode(GL_MODELVIEW);
     glLoadIdentity;
-//    glTranslatef(0.5, 0.5, 0);
+    glEnable(GL_SCISSOR_TEST);
+    r_Draw_SetRect(0, 0, w - 1, h - 1);
   end;
 
   procedure DrawQuad (x, y, w, h: Integer);
index 0619108abcd45036b8d861e2141e4572a211dae5..b6fa9d6569016772a7198396a987cbad727ad299 100644 (file)
@@ -63,29 +63,31 @@ implementation
     Font[FALSE] := smallfont;
     Font[TRUE] := menufont;
 
-    MarkerID[FALSE] := r_Textures_LoadFromFile(GameWad + ':TEXTURES/MARKER1');
-    MarkerID[TRUE] := r_Textures_LoadFromFile(GameWad + ':TEXTURES/MARKER2');
+    r_Common_SetLoading('GUI', 2 + 9 + 14);
+
+    MarkerID[FALSE] := r_Common_LoadTextureFromFile(GameWad + ':TEXTURES/MARKER1');
+    MarkerID[TRUE] := r_Common_LoadTextureFromFile(GameWad + ':TEXTURES/MARKER2');
 
     for i := 0 to 8 do
-      Box[i] := r_Textures_LoadFromFile(GameWad + ':TEXTURES/BOX' + IntToStr(i + 1));
+      Box[i] := r_Common_LoadTextureFromFile(GameWad + ':TEXTURES/BOX' + IntToStr(i + 1));
 
-    ScrollLeft := r_Textures_LoadFromFile(GameWad + ':TEXTURES/SLEFT');
-    ScrollRight := r_Textures_LoadFromFile(GameWad + ':TEXTURES/SRIGHT');
-    ScrollMiddle := r_Textures_LoadFromFile(GameWad + ':TEXTURES/SMIDDLE');
-    ScrollMarker := r_Textures_LoadFromFile(GameWad + ':TEXTURES/SMARKER');
+    ScrollLeft := r_Common_LoadTextureFromFile(GameWad + ':TEXTURES/SLEFT');
+    ScrollRight := r_Common_LoadTextureFromFile(GameWad + ':TEXTURES/SRIGHT');
+    ScrollMiddle := r_Common_LoadTextureFromFile(GameWad + ':TEXTURES/SMIDDLE');
+    ScrollMarker := r_Common_LoadTextureFromFile(GameWad + ':TEXTURES/SMARKER');
 
-    EditLeft := r_Textures_LoadFromFile(GameWad + ':TEXTURES/ELEFT');
-    EditRight := r_Textures_LoadFromFile(GameWad + ':TEXTURES/ERIGHT');
-    EditMiddle := r_Textures_LoadFromFile(GameWad + ':TEXTURES/EMIDDLE');
+    EditLeft := r_Common_LoadTextureFromFile(GameWad + ':TEXTURES/ELEFT');
+    EditRight := r_Common_LoadTextureFromFile(GameWad + ':TEXTURES/ERIGHT');
+    EditMiddle := r_Common_LoadTextureFromFile(GameWad + ':TEXTURES/EMIDDLE');
 
-    BScrollUp[true] := r_Textures_LoadFromFile(GameWad + ':TEXTURES/SCROLLUPA');
-    BScrollUp[false] := r_Textures_LoadFromFile(GameWad + ':TEXTURES/SCROLLUPU');
-    BScrollDown[true] := r_Textures_LoadFromFile(GameWad + ':TEXTURES/SCROLLDOWNA');
-    BScrollDown[false] := r_Textures_LoadFromFile(GameWad + ':TEXTURES/SCROLLDOWNU');
-    BScrollMiddle := r_Textures_LoadFromFile(GameWad + ':TEXTURES/SCROLLMIDDLE');
+    BScrollUp[true] := r_Common_LoadTextureFromFile(GameWad + ':TEXTURES/SCROLLUPA');
+    BScrollUp[false] := r_Common_LoadTextureFromFile(GameWad + ':TEXTURES/SCROLLUPU');
+    BScrollDown[true] := r_Common_LoadTextureFromFile(GameWad + ':TEXTURES/SCROLLDOWNA');
+    BScrollDown[false] := r_Common_LoadTextureFromFile(GameWad + ':TEXTURES/SCROLLDOWNU');
+    BScrollMiddle := r_Common_LoadTextureFromFile(GameWad + ':TEXTURES/SCROLLMIDDLE');
 
-    LogoTex := r_Textures_LoadFromFile(GameWad + ':TEXTURES/MAINLOGO');
-    nopic := r_Textures_LoadFromFile(GameWad + ':TEXTURES/NOPIC');
+    LogoTex := r_Common_LoadTextureFromFile(GameWad + ':TEXTURES/MAINLOGO');
+    nopic := r_Common_LoadTextureFromFile(GameWad + ':TEXTURES/NOPIC');
   end;
 
   procedure r_GUI_Free;
diff --git a/src/game/renders/opengl/r_loadscreen.pas b/src/game/renders/opengl/r_loadscreen.pas
new file mode 100644 (file)
index 0000000..8b9ce80
--- /dev/null
@@ -0,0 +1,184 @@
+(* Copyright (C)  Doom 2D: Forever Developers
+ *
+ * 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, version 3 of the License ONLY.
+ *
+ * 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.  If not, see <http://www.gnu.org/licenses/>.
+ *)
+{$INCLUDE ../../../shared/a_modes.inc}
+unit r_loadscreen;
+
+interface
+
+  procedure r_LoadScreen_Initialize;
+  procedure r_LoadScreen_Finalize;
+
+  procedure r_LoadScreen_Load;
+  procedure r_LoadScreen_Free;
+
+  procedure r_LoadScreen_Clear;
+  procedure r_LoadScreen_Set (const text: AnsiString; maxval: Integer);
+  procedure r_LoadScreen_Step (incval: Integer);
+  procedure r_LoadScreen_Draw (force: Boolean);
+
+implementation
+
+  uses
+    {$IFDEF USE_GLES1}
+      GLES11,
+    {$ELSE}
+      GL, GLEXT,
+    {$ENDIF}
+    {$IFDEF ENABLE_SYSTEM}
+      g_system,
+    {$ENDIF}
+    SysUtils, Classes, Math,
+    e_log, utils, g_language, g_options, g_console, g_game,
+    r_draw, r_textures, r_fonts, r_common, r_console
+  ;
+
+  var
+    FPSTime: LongWord = 0;
+    r_loadscreen_fps: WORD = 0;
+    BarL, BarM, BarR, BarF: TGLTexture;
+    LoadingScreen: array of record
+      msg: AnsiString;
+      val, maxval: Integer;
+    end = nil;
+
+  procedure r_LoadScreen_Initialize;
+  begin
+  end;
+
+  procedure r_LoadScreen_Finalize;
+  begin
+  end;
+
+  procedure r_LoadScreen_Load;
+  begin
+    BarL := r_Textures_LoadFromFile(GameWAD + ':TEXTURES/LLEFT');
+    BarM := r_Textures_LoadFromFile(GameWAD + ':TEXTURES/LMIDDLE');
+    BarR := r_Textures_LoadFromFile(GameWAD + ':TEXTURES/LRIGHT');
+    BarF := r_Textures_LoadFromFile(GameWAD + ':TEXTURES/LMARKER');
+  end;
+
+  procedure r_LoadScreen_Free;
+  begin
+    BarL.Free;
+    BarM.Free;
+    BarR.Free;
+    BarF.Free;
+  end;
+
+  procedure r_LoadScreen_DrawLoadingBar (x0, x1, y, val, maxval: Integer);
+    var l, t, r, b, minw, reqw, midw, fillw, curw, x: Integer;
+  begin
+    if (BarL <> nil) and (BarM <> nil) and (BarR <> nil) and (BarF <> nil) and (maxval > 0) then
+    begin
+      minw := BarL.width + BarM.width + BarR.width;
+      reqw := x1 - x0;
+      if reqw >= minw then
+      begin
+        midw := (reqw - BarL.width - BarR.width) div BarM.width * BarM.width;
+        x := x0 - (reqw - (BarL.width + midw + BarR.width)) div 2;
+        fillw := midw + 2;
+        curw := MIN(val * fillw div maxval, fillw);
+        r_Draw_TextureRepeat(BarL, x, y, BarL.width, BarL.height, false, 255, 255, 255, 255, false);
+        r_Draw_TextureRepeat(BarM, x + BarL.width, y, midw, BarM.height, false, 255, 255, 255, 255, false);
+        r_Draw_TextureRepeat(BarR, x + BarL.width + midw, y, BarR.width, BarR.height, false, 255, 255, 255, 255, false);
+        if curw > 0 then
+        begin
+          r_Draw_GetRect(l, t, r, b);
+          r_Draw_SetRect(x + BarL.width - 1, y, x + BarL.width - 1 + curw - 1, y + BarF.height - 1);
+          r_Draw_TextureRepeat(BarF, x + BarL.width - 1, y, curw, BarF.height, false, 255, 255, 255, 255, false);
+          r_Draw_SetRect(l, t, r, b);
+        end;
+      end;
+    end;
+  end;
+
+  procedure r_LoadScreen_Clear;
+  begin
+    LoadingScreen := nil;
+  end;
+
+  procedure r_LoadScreen_Set (const text: String; maxval: Integer);
+    var i: Integer;
+  begin
+    if LoadingScreen = nil then i := 0 else i := Length(LoadingScreen);
+    SetLength(LoadingScreen, i + 1);
+    LoadingScreen[i].msg := text;
+    LoadingScreen[i].val := 0;
+    LoadingScreen[i].maxval := MAX(0, maxval);
+  end;
+
+  procedure r_LoadScreen_Step (incval: Integer);
+    var i: Integer;
+  begin
+    if LoadingScreen <> nil then
+    begin
+      i := HIGH(LoadingScreen);
+      INC(LoadingScreen[i].val, MAX(0, incval));
+    end;
+  end;
+
+  procedure r_LoadScreen_Draw (force: Boolean);
+    const LOADING_INTERLINE = 20;
+    var xx, yy, hh, i, n: Integer; s: AnsiString; time, delay: LongWord;
+  begin
+    time := GetTickCount64();
+    if r_loadscreen_fps <= 0 then delay := 1000 div GAME_TICK else delay := 1000 div r_loadscreen_fps;
+    if force or (time - FPSTime >= delay) then
+    begin
+      FPSTime := time;
+
+      xx := gScreenWidth div 3;
+      yy := gScreenHeight div 3;
+      hh := gScreenHeight - yy - 96;
+      r_Draw_Setup(gScreenWidth, gScreenHeight);
+      glClearColor(0.0, 0.0, 0.0, 0.0);
+      glClear(GL_COLOR_BUFFER_BIT or GL_DEPTH_BUFFER_BIT);
+      r_Common_DrawBackground(GameWad + ':TEXTURES/INTER');
+      r_Draw_FillRect(0, 0, gScreenWidth - 1, gScreenHeight - 1, 0, 0, 0, 105);
+      if menufont <> nil then
+      begin
+        r_Common_DrawText(_lc[I_MENU_LOADING], gScreenWidth div 2, yy - 32, 255, 255, 255, 255, menufont, TBasePoint.BP_DOWN);
+      end;
+      if (smallfont <> nil) and (LoadingScreen <> nil) then
+      begin
+        n := hh div LOADING_INTERLINE - 1;
+        for i := MAX(0, Length(LoadingScreen) - n) to HIGH(LoadingScreen) do
+        begin
+          if LoadingScreen[i].maxval > 1 then
+            s := LoadingScreen[i].msg + '  ' + IntToStr(LoadingScreen[i].val) + '/' + IntToStr(LoadingScreen[i].maxval)
+          else
+            s := LoadingScreen[i].msg;
+          r_Common_DrawText(s, xx, yy, 255, 0, 0, 255, smallfont, TBasePoint.BP_LEFTUP);
+          INC(yy, LOADING_INTERLINE);
+        end;
+      end;
+      if (BarF <> nil) and (LoadingScreen <> nil) then
+      begin
+        i := HIGH(LoadingScreen);
+        if LoadingScreen[i].maxval > 1 then
+          r_LoadScreen_DrawLoadingBar(64, gScreenWidth - 64, gScreenHeight - 64, LoadingScreen[i].val, LoadingScreen[i].maxval);
+      end;
+      if stdfont <> nil then
+      begin
+        r_Console_Draw(true);
+      end;
+      sys_Repaint;
+    end;
+  end;
+
+initialization
+  conRegVar('r_loadscreen_fps', @r_loadscreen_fps, '', '');
+  r_loadscreen_fps := 0; // auto
+end.
index 535d56eeafd6ca3456eec9fe2359f2ab75ec81e9..2ca87d7ec2431ca5bfe12c71a1f3c533f469641a 100644 (file)
@@ -55,7 +55,7 @@ implementation
     binheap, MAPDEF, utils,
     g_options, g_animations, g_basic, g_phys,
     g_game, g_map, g_panel, g_items, g_monsters, g_weapons,
-    g_console,
+    g_console, g_language,
     {$IFDEF ENABLE_CORPSES}
       g_corpses,
     {$ENDIF}
@@ -411,9 +411,10 @@ implementation
       i, j, k: Integer; d: TDirection; b: Boolean;
   begin
     // --------- items --------- //
+    r_Common_SetLoading(_lc[I_LOAD_ITEMS_DATA], ITEM_LAST + 1);
     for i := 0 to ITEM_LAST do
     begin
-      Items[i].tex := r_Textures_LoadMultiFromFileAndInfo(
+      Items[i].tex := r_Common_LoadTextureMultiFromFileAndInfo(
         GameWAD + ':TEXTURES/' + ItemAnim[i].name,
         ItemAnim[i].w,
         ItemAnim[i].h,
@@ -423,53 +424,73 @@ implementation
       Items[i].frame := 0;
     end;
     // --------- monsters --------- //
+    r_Common_SetLoading(_lc[I_LOAD_MONSTER_TEXTURES], MONSTER_MAN - MONSTER_DEMON + 1);
     for i := MONSTER_DEMON to MONSTER_MAN do
+    begin
       for j := 0 to ANIM_LAST do
         for d := TDirection.D_LEFT to TDirection.D_RIGHT do
           r_Map_LoadMonsterAnim(i, j, d);
+      r_Common_StepLoading(1);
+    end;
     VileFire := r_Textures_LoadMultiFromFileAndInfo(GameWAD + ':TEXTURES/FIRE', 64, 128, VileFireAnim.frames);
     // --------- player models --------- //
     if PlayerModelsArray <> nil then
     begin
+      r_Common_SetLoading(_lc[I_LOAD_MODELS], Length(PlayerModelsArray));
       SetLength(Models, Length(PlayerModelsArray));
       for i := 0 to High(PlayerModelsArray) do
+      begin
         r_Map_LoadModel(i);
+        r_Common_StepLoading(1);
+      end;
     end;
     // --------- player weapons --------- //
+    r_Common_SetLoading(_lc[I_LOAD_WEAPONS_DATA], WP_LAST);
     for i := 1 to WP_LAST do
+    begin
       for j := 0 to W_POS_LAST do
         for k := 0 to W_ACT_LAST do
           WeapTextures[i, j, k] := r_Textures_LoadFromFile(GameWAD + ':WEAPONS\' + WeapName[i] + WeapPos[j] + WeapAct[k]);
+      r_Common_StepLoading(1);
+    end;
     // --------- gfx animations --------- //
     {$IFDEF ENABLE_GFX}
+      r_Common_SetLoading('GFX Effects', R_GFX_LAST);
       for i := 1 to R_GFX_LAST do
+      begin
         if GFXAnim[i].anim.frames > 0 then
-          GFXTextures[i] := r_Textures_LoadMultiFromFileAndInfo(GameWad + ':TEXTURES/' + GFXAnim[i].name, GFXAnim[i].w, GFXAnim[i].h, GFXAnim[i].anim.frames);
+          GFXTextures[i] := r_Common_LoadTextureMultiFromFileAndInfo(GameWad + ':TEXTURES/' + GFXAnim[i].name, GFXAnim[i].w, GFXAnim[i].h, GFXAnim[i].anim.frames);
+      end;
     {$ENDIF}
     // --------- shots --------- //
+    r_Common_SetLoading('Weapon splahses', WEAPON_LAST + 1);
     for i := 0 to WEAPON_LAST do
+    begin
       if ShotAnim[i].anim.frames > 0 then
-        ShotTextures[i] := r_Textures_LoadMultiFromFileAndInfo(GameWad + ':TEXTURES/' + ShotAnim[i].name, ShotAnim[i].w, ShotAnim[i].h, ShotAnim[i].anim.frames);
+        ShotTextures[i] := r_Common_LoadTextureMultiFromFileAndInfo(GameWad + ':TEXTURES/' + ShotAnim[i].name, ShotAnim[i].w, ShotAnim[i].h, ShotAnim[i].anim.frames);
+    end;
     // --------- flags --------- //
+    r_Common_SetLoading('Flags', 2);
     FlagTextures[FLAG_NONE] := nil;
-    FlagTextures[FLAG_RED]  := r_Textures_LoadMultiFromFileAndInfo(GameWad + ':TEXTURES/FLAGRED',  64, 64, 5);
-    FlagTextures[FLAG_BLUE] := r_Textures_LoadMultiFromFileAndInfo(GameWad + ':TEXTURES/FLAGBLUE', 64, 64, 5);
-    // FlagTextures[FLAG_DOM]  := r_Textures_LoadMultiFromFileAndInfo(GameWad + ':TEXTURES/FLAGDOM',  64, 64, 8);
+    FlagTextures[FLAG_RED]  := r_Common_LoadTextureMultiFromFileAndInfo(GameWad + ':TEXTURES/FLAGRED',  64, 64, 5);
+    FlagTextures[FLAG_BLUE] := r_Common_LoadTextureMultiFromFileAndInfo(GameWad + ':TEXTURES/FLAGBLUE', 64, 64, 5);
+    // FlagTextures[FLAG_DOM]  := r_Common_LoadTextureMultiFromFileAndInfo(GameWad + ':TEXTURES/FLAGDOM',  64, 64, 8);
     // --------- shells --------- //
     {$IFDEF ENABLE_SHELLS}
+      r_Common_SetLoading('Shells', SHELL_LAST + 1);
       for i := 0 to SHELL_LAST do
-        ShellTextures[i] := r_Textures_LoadFromFile(GameWad + ':TEXTURES/' + ShellAnim[i].name);
+        ShellTextures[i] := r_Common_LoadTextureFromFile(GameWad + ':TEXTURES/' + ShellAnim[i].name);
     {$ENDIF}
-    // --------- punch --------- //
+    // --------- other --------- //
+    r_Common_SetLoading('Effects', 3 * 2 + 3);
     for b := false to true do
     begin
       for i := 0 to 2 do
-        PunchTextures[b, i] := r_Textures_LoadMultiFromFileAndInfo(GameWad + ':WEAPONS/' + PunchName[b] + WeapPos[i], 64, 64, PunchAnim.frames);
+        PunchTextures[b, i] := r_Common_LoadTextureMultiFromFileAndInfo(GameWad + ':WEAPONS/' + PunchName[b] + WeapPos[i], 64, 64, PunchAnim.frames);
     end;
-    // --------- other --------- //
-    InvulPenta := r_Textures_LoadFromFile(GameWad + ':TEXTURES/PENTA');
-    IndicatorTexture := r_Textures_LoadFromFile(GameWad + ':TEXTURES/PLRIND');
-    TalkTexture := r_Textures_LoadFromFile(GameWad + ':TEXTURES/TALKBUBBLE');
+    InvulPenta := r_Common_LoadTextureFromFile(GameWad + ':TEXTURES/PENTA');
+    IndicatorTexture := r_Common_LoadTextureFromFile(GameWad + ':TEXTURES/PLRIND');
+    TalkTexture := r_Common_LoadTextureFromFile(GameWad + ':TEXTURES/TALKBUBBLE');
   end;
 
   procedure r_Map_Free;
@@ -563,6 +584,7 @@ implementation
     begin
       n := Length(Textures);
       SetLength(RenTextures, n);
+      r_Common_SetLoading(_lc[I_LOAD_TEXTURES], n);
       for i := 0 to n - 1 do
       begin
         txt.anim := DefaultAnimInfo;
@@ -573,17 +595,20 @@ implementation
           TEXTURE_NAME_ACID2: RenTextures[i].spec := TEXTURE_SPECIAL_ACID2;
           else
             RenTextures[i].spec := 0;
-            e_LogWritefln('r_Map_LoadTextures: begin load texture: %s', [Textures[i].FullName]);
             RenTextures[i].tex := r_Textures_LoadMultiTextFromFile(Textures[i].FullName, txt);
-            e_LogWritefln('r_Map_LoadTextures: end load texture: %s', [Textures[i].FullName]);
             if RenTextures[i].tex = nil then
-              e_LogWritefln('r_Map_LoadTextures: failed to load texture: %s', [Textures[i].FullName]);
+              e_LogWritefln('r_Map_LoadTextures: failed to load texture: %s', [Textures[i].FullName])
+            else
+              r_Common_StepLoading(1);
         end;
         RenTextures[i].anim := txt.anim;
       end;
     end;
     if gMapInfo.SkyFullName <> '' then
-      SkyTexture := r_Textures_LoadFromFile(gMapInfo.SkyFullName);
+    begin
+      r_Common_SetLoading(_lc[I_LOAD_SKY], 1);
+      SkyTexture := r_Common_LoadTextureFromFile(gMapInfo.SkyFullName);
+    end;
     plist.Clear;
   end;
 
index a11ca7fc02fbf4843d4b051c25532c59a54a7165..5a6bb2745ff53aa886567b9f917f47406c38dd1f 100644 (file)
@@ -24,6 +24,9 @@ interface
     g_base // TRectWH
   ;
 
+  type
+    TProcedure = procedure;
+
   (* render startup *)
   procedure r_Render_Initialize;
   procedure r_Render_Finalize;
@@ -64,7 +67,11 @@ interface
     procedure r_Render_GetStringSize (BigFont: Boolean; str: String; out w, h: Integer);
   {$ENDIF}
 
-  procedure r_Render_DrawLoading (force: Boolean); // !!! remove it
+  procedure r_Render_SetProcessLoadingCallback (p: TProcedure);
+  procedure r_Render_ClearLoading;
+  procedure r_Render_SetLoading (const text: String; maxval: Integer);
+  procedure r_Render_StepLoading (incval: Integer);
+  procedure r_Render_DrawLoading (force: Boolean);
 
 implementation
 
@@ -85,12 +92,10 @@ implementation
     e_log, utils, wadreader, mapdef,
     g_game, g_map, g_panel, g_options, g_console, g_player, g_weapons, g_language, g_triggers, g_monsters,
     g_net, g_netmaster,
-    r_draw, r_textures, r_fonts, r_common, r_console, r_map
+    r_draw, r_textures, r_fonts, r_common, r_console, r_map, r_loadscreen
   ;
 
   var
-    BackgroundTexture: THereTexture;
-
     hud, hudbg: TGLTexture;
     hudhp: array [Boolean] of TGLTexture;
     hudap: TGLTexture;
@@ -119,26 +124,27 @@ implementation
     var
       i: Integer;
   begin
+    r_LoadScreen_Load;
     r_Common_Load;
-    BackgroundTexture := DEFAULT(THereTexture);
-    hud :=  r_Textures_LoadFromFile(GameWAD + ':TEXTURES/HUD');
-    hudbg :=  r_Textures_LoadFromFile(GameWAD + ':TEXTURES/HUDBG');
-    hudhp[false] := r_Textures_LoadFromFile(GameWAD + ':TEXTURES/MED2');
-    hudhp[true] := r_Textures_LoadFromFile(GameWAD + ':TEXTURES/BMED');
-    hudap := r_Textures_LoadFromFile(GameWAD + ':TEXTURES/ARMORHUD');
+    r_Common_SetLoading('HUD Textures', 5 + (WP_LAST + 1) + 11);
+    hud :=  r_Common_LoadTextureFromFile(GameWAD + ':TEXTURES/HUD');
+    hudbg :=  r_Common_LoadTextureFromFile(GameWAD + ':TEXTURES/HUDBG');
+    hudhp[false] := r_Common_LoadTextureFromFile(GameWAD + ':TEXTURES/MED2');
+    hudhp[true] := r_Common_LoadTextureFromFile(GameWAD + ':TEXTURES/BMED');
+    hudap := r_Common_LoadTextureFromFile(GameWAD + ':TEXTURES/ARMORHUD');
     for i := 0 to WP_LAST do
-      hudwp[i] := r_Textures_LoadFromFile(GameWAD + ':TEXTURES/' + WeapName[i]);
-    hudkey[0] := r_Textures_LoadFromFile(GameWAD + ':TEXTURES/KEYR');
-    hudkey[1] := r_Textures_LoadFromFile(GameWAD + ':TEXTURES/KEYG');
-    hudkey[2] := r_Textures_LoadFromFile(GameWAD + ':TEXTURES/KEYB');
-    hudair := r_Textures_LoadFromFile(GameWAD + ':TEXTURES/AIRBAR');
-    hudjet := r_Textures_LoadFromFile(GameWAD + ':TEXTURES/JETBAR');
-    hudrflag := r_Textures_LoadFromFile(GameWAD + ':TEXTURES/FLAGHUD_R_BASE');
-    hudrflags := r_Textures_LoadFromFile(GameWAD + ':TEXTURES/FLAGHUD_R_STOLEN');
-    hudrflagd := r_Textures_LoadFromFile(GameWAD + ':TEXTURES/FLAGHUD_R_DROP');
-    hudbflag := r_Textures_LoadFromFile(GameWAD + ':TEXTURES/FLAGHUD_B_BASE');
-    hudbflags := r_Textures_LoadFromFile(GameWAD + ':TEXTURES/FLAGHUD_B_STOLEN');
-    hudbflagd := r_Textures_LoadFromFile(GameWAD + ':TEXTURES/FLAGHUD_B_DROP');
+      hudwp[i] := r_Common_LoadTextureFromFile(GameWAD + ':TEXTURES/' + WeapName[i]);
+    hudkey[0] := r_Common_LoadTextureFromFile(GameWAD + ':TEXTURES/KEYR');
+    hudkey[1] := r_Common_LoadTextureFromFile(GameWAD + ':TEXTURES/KEYG');
+    hudkey[2] := r_Common_LoadTextureFromFile(GameWAD + ':TEXTURES/KEYB');
+    hudair := r_Common_LoadTextureFromFile(GameWAD + ':TEXTURES/AIRBAR');
+    hudjet := r_Common_LoadTextureFromFile(GameWAD + ':TEXTURES/JETBAR');
+    hudrflag := r_Common_LoadTextureFromFile(GameWAD + ':TEXTURES/FLAGHUD_R_BASE');
+    hudrflags := r_Common_LoadTextureFromFile(GameWAD + ':TEXTURES/FLAGHUD_R_STOLEN');
+    hudrflagd := r_Common_LoadTextureFromFile(GameWAD + ':TEXTURES/FLAGHUD_R_DROP');
+    hudbflag := r_Common_LoadTextureFromFile(GameWAD + ':TEXTURES/FLAGHUD_B_BASE');
+    hudbflags := r_Common_LoadTextureFromFile(GameWAD + ':TEXTURES/FLAGHUD_B_STOLEN');
+    hudbflagd := r_Common_LoadTextureFromFile(GameWAD + ':TEXTURES/FLAGHUD_B_DROP');
     r_Console_Load;
     r_Map_Load;
     {$IFDEF ENABLE_MENU}
@@ -176,7 +182,6 @@ implementation
     hudhp[false].Free;
     hudbg.Free;
     hud.Free;
-    r_Common_FreeThis(BackgroundTexture);
     r_Common_Free;
   end;
 
@@ -204,6 +209,7 @@ implementation
         raise Exception.Create('Failed to set videomode on startup.');
       sys_EnableVSync(gVSync);
     {$ENDIF}
+    r_LoadScreen_Initialize;
     r_Textures_Initialize;
     r_Console_Initialize;
     r_Map_Initialize;
@@ -214,6 +220,7 @@ implementation
     r_Map_Finalize;
     r_Console_Finalize;
     r_Textures_Finalize;
+    r_LoadScreen_Finalize;
   end;
 
   procedure r_Render_Update;
@@ -420,24 +427,6 @@ implementation
     r_Draw_SetRect(l, t, r, b);
   end;
 
-  procedure r_Render_DrawBackgroundImage (img: TGLTexture);
-    var fw, w, h: LongInt;
-  begin
-    if img <> nil then
-    begin
-      img := BackgroundTexture.id;
-      if img.width = img.height then fw := img.width * 4 div 3 else fw := img.width; // fix aspect 4:3
-      r_Common_CalcAspect(fw, img.height, gScreenWidth, gScreenHeight, false, w, h);
-      r_Draw_Texture(img, gScreenWidth div 2 - w div 2, 0, w, h, false, 255, 255, 255, 255, false);
-    end
-  end;
-
-  procedure r_Render_DrawBackground (const name: AnsiString);
-  begin
-    if r_Common_LoadThis(name, BackgroundTexture) then
-      r_Render_DrawBackgroundImage(BackgroundTexture.id)
-  end;
-
   procedure r_Render_DrawServerList (var SL: TNetServerList; var ST: TNetServerTable);
     var ip: AnsiString; ww, hh, cw, ch, mw, mh, motdh, scrx, scry, i, mx, y: Integer; msg: SSArray; Srv: TNetServer;
   begin
@@ -459,7 +448,7 @@ implementation
     begin
       r_Draw_FillRect(16, motdh, gScreenWidth - 16, gScreenHeight - 44, 64, 64, 64, 110);
       r_Draw_Rect(16, motdh, gScreenWidth - 16, gScreenHeight - 44, 255, 127, 0, 255);
-      r_Common_DrawFormatText(slMOTD, 20, motdh + 3 + ch * i, 255, stdfont, TBasePoint.BP_LEFTUP);
+      r_Common_DrawFormatText(slMOTD, 20, motdh + 3, 255, stdfont, TBasePoint.BP_LEFTUP);
     end;
 
     if not slReadUrgent and (slUrgent <> '') then
@@ -469,7 +458,7 @@ implementation
       r_Draw_Rect(scrx - 256, scry - 60, scrx + 256, scry + 60, 255, 127, 0, 255);
       r_Draw_FillRect(scrx - 256, scry - 40, scrx + 256, scry - 40, 255, 127, 0, 255);
       r_Common_DrawText(_lc[I_NET_SLIST_URGENT], scrx, scry - 58, 255, 255, 255, 255, stdfont, TBasePoint.BP_UP);
-      r_Common_DrawFormatText(slUrgent, scrx - 253, scry - 38 + ch * i, 255, stdfont, TBasePoint.BP_LEFTUP);
+      r_Common_DrawFormatText(slUrgent, scrx - 253, scry - 38, 255, stdfont, TBasePoint.BP_LEFTUP);
       r_Common_DrawText(_lc[I_NET_SLIST_URGENT_CONT], scrx, scry + 41, 255, 255, 255, 255, stdfont, TBasePoint.BP_UP);
       r_Draw_FillRect(scrx - 256, scry + 40, scrx + 256, scry + 40, 255, 127, 0, 255);
     end
@@ -1060,12 +1049,6 @@ implementation
     glClearColor(0.0, 0.0, 0.0, 0.0);
     glClear(GL_COLOR_BUFFER_BIT or GL_DEPTH_BUFFER_BIT);
 
-    glColor4ub(255, 255, 255, 255);
-    glEnable(GL_SCISSOR_TEST);
-    r_Draw_SetRect(0, 0, gScreenWidth, gScreenHeight);
-
-    //e_LogWritefln('r_render_draw: %sx%s', [gScreenWidth, gScreenHeight]);
-
     p1 := nil;
     p2 := nil;
     if gGameOn or (gState = STATE_FOLD) then
@@ -1151,7 +1134,7 @@ implementation
       // TODO F key handle
       case gState of
         STATE_NONE: (* do nothing *) ;
-        STATE_MENU: r_Render_DrawBackground(GameWad + ':TEXTURES/TITLE');
+        STATE_MENU: r_Common_DrawBackground(GameWad + ':TEXTURES/TITLE');
         STATE_FOLD:
         begin
           if EndingGameCounter > 0 then
@@ -1161,11 +1144,11 @@ implementation
         begin
           if gLastMap and (gGameSettings.GameMode = GM_COOP) then
             if EndPicPath <> '' then
-              r_Render_DrawBackground(EndPicPath)
+              r_Common_DrawBackground(EndPicPath)
             else
-              r_Render_DrawBackground(GameWad + ':TEXTURES/' + _lc[I_TEXTURE_ENDPIC])
+              r_Common_DrawBackground(GameWad + ':TEXTURES/' + _lc[I_TEXTURE_ENDPIC])
           else
-            r_Render_DrawBackground(GameWad + ':TEXTURES/INTER');
+            r_Common_DrawBackground(GameWad + ':TEXTURES/INTER');
 
           r_Render_DrawCustomStats;
 
@@ -1182,7 +1165,7 @@ implementation
           end
           else
           begin
-            r_Render_DrawBackground(GameWad + ':TEXTURES/INTER');
+            r_Common_DrawBackground(GameWad + ':TEXTURES/INTER');
             r_Render_DrawSingleStats;
             {$IFDEF ENABLE_MENU}
               if g_ActiveWindow <> nil then
@@ -1193,9 +1176,9 @@ implementation
         STATE_ENDPIC:
         begin
           if EndPicPath <> '' then
-            r_Render_DrawBackground(EndPicPath)
+            r_Common_DrawBackground(EndPicPath)
           else
-            r_Render_DrawBackground(GameWad + ':TEXTURES/' + _lc[I_TEXTURE_ENDPIC]);
+            r_Common_DrawBackground(GameWad + ':TEXTURES/' + _lc[I_TEXTURE_ENDPIC]);
           {$IFDEF ENABLE_MENU}
             if g_ActiveWindow <> nil then
               r_Draw_FillRect(0, 0, gScreenWidth - 1, gScreenHeight - 1, 0, 0, 0, 105);
@@ -1203,7 +1186,7 @@ implementation
         end;
         STATE_SLIST:
         begin
-          r_Render_DrawBackground(GameWad + ':TEXTURES/TITLE');
+          r_Common_DrawBackground(GameWad + ':TEXTURES/TITLE');
           r_Draw_FillRect(0, 0, gScreenWidth - 1, gScreenHeight - 1, 0, 0, 0, 105);
           r_Render_DrawServerList(slCurrent, slTable);
         end;
@@ -1240,8 +1223,6 @@ implementation
 
     // TODO draw touch screen controls
 
-    glFlush();
-    glFinish();
     sys_Repaint;
   end;
 
@@ -1316,9 +1297,29 @@ implementation
   end;
 {$ENDIF}
 
+  procedure r_Render_SetProcessLoadingCallback (p: TProcedure);
+  begin
+    r_Common_ProcessLoadingCallback := p;
+  end;
+
+  procedure r_Render_ClearLoading;
+  begin
+    r_Common_ClearLoading;
+  end;
+
+  procedure r_Render_SetLoading (const text: String; maxval: Integer);
+  begin
+    r_Common_SetLoading(text, maxval);
+  end;
+
+  procedure r_Render_StepLoading (incval: Integer);
+  begin
+    r_Common_StepLoading(incval);
+  end;
+
   procedure r_Render_DrawLoading (force: Boolean);
   begin
-    // TODO draw loading screen
+    r_Common_DrawLoading(force);
   end;
 
 end.