R-Type
Distributed multiplayer game engine in C++
Loading...
Searching...
No Matches
Rendering.cpp
Go to the documentation of this file.
1/*
2** EPITECH PROJECT, 2025
3** Created by samuelBleau on 26/11/2025.
4** File description:
5** Rendering.cpp
6*/
7
8#include "Rendering.hpp"
9#include <thread>
10#include "Events/UIEvent.hpp"
11#include "Input/KeyBindings.hpp"
13#include "UI/TextUtils.hpp"
14
15Rendering::Rendering(EventBus &eventBus) : _eventBus(eventBus) {
16 // Note: Window creation is deferred to Initialize()
17 // This allows GameLoop to control initialization timing
18 _entityRenderer = std::make_unique<EntityRenderer>(_graphics);
19}
20
24
25bool Rendering::Initialize(uint32_t width, uint32_t height, const std::string &title) {
26 if (_initialized) {
27 LOG_WARNING("Rendering already initialized, skipping");
28 return true;
29 }
30
31 _graphics.InitWindow(static_cast<int>(width), static_cast<int>(height), title.c_str());
32
33 _width = width;
34 _height = height;
35
36 _quitRequested = false;
37
38 _showPing = true;
39 _showFps = true;
40
41 _fps = 0;
42 _fpsAccumulator = 0.0f;
44
47
48 // Start with server selection menu
49 _entityRenderer.reset();
50
51 _initialized = true;
52 LOG_INFO("Rendering initialized: ", width, "x", height, " (", title, ")");
53 return true;
54}
55
57 _uiFactory = std::make_unique<UI::RaylibUIFactory>(_graphics);
58
59 // Load saved key bindings
61 // Initialize sound effect manager for UI sounds
62 _soundEffectManager = std::make_unique<Audio::SoundEffectManager>(_graphics);
63 if (!_soundEffectManager->Initialize()) {
64 LOG_WARNING("[Rendering] Sound effect manager initialization failed - sounds disabled");
65 }
66
71
72 // Load saved accessibility settings (after accessibility menu is created)
74
87}
88
90 // Default: 60 FPS cap at startup
92
93 // Keep menu button state consistent with renderer state (silent sync)
94 if (_settingsMenu) {
95 _settingsMenu->SetTargetFpsSilent(60);
96 _settingsMenu->SetShowPingSilent(_showPing);
97 _settingsMenu->SetShowFpsSilent(_showFps);
98 _settingsMenu->RefreshVisuals();
99 }
100}
101
102// ===== Menu Initialization Functions (SOLID: Single Responsibility) =====
103
105 _confirmQuitMenu = std::make_unique<Game::ConfirmQuitMenu>(*_uiFactory);
106 _confirmQuitMenu->SetSoundEffectService(_soundEffectManager.get());
107
108 _confirmQuitMenu->SetOnConfirm([this]() { _quitRequested = true; });
109
110 _confirmQuitMenu->SetOnCancel([this]() {
111 if (_confirmQuitMenu) {
112 _confirmQuitMenu->Hide();
113 }
114 _confirmQuitOverlay = false;
115
116 // Return to previous UI depending on scene
117 if (_scene == Scene::MENU) {
118 if (_mainMenu) {
119 _mainMenu->Show();
120 }
121 }
122 });
123
124 _confirmQuitMenu->Initialize();
125 _confirmQuitMenu->Hide();
126}
127
129 _settingsMenu = std::make_unique<Game::SettingsMenu>(*_uiFactory, _graphics);
130 _settingsMenu->SetSoundEffectService(_soundEffectManager.get());
132
133 _settingsMenu->SetOnShowPingChanged([this](bool enabled) { SetShowPing(enabled); });
134
135 _settingsMenu->SetOnShowFpsChanged([this](bool enabled) { SetShowFps(enabled); });
136
137 _settingsMenu->SetOnShowChatChanged([this](bool enabled) {
138 if (_chatWidget) {
139 _chatWidget->SetVisible(enabled);
140 }
141 });
142
143 _settingsMenu->SetOnAutoMatchmakingChanged([this](bool enabled) {
144 LOG_INFO("[Rendering] Auto-matchmaking preference ", enabled ? "enabled" : "disabled");
145 // Publish event to update preference on server (NOT to trigger matchmaking)
146 _eventBus.publish(UIEvent(UIEventType::UPDATE_AUTO_MATCHMAKING_PREF, enabled ? "enable" : "disable"));
147 });
148
149 _settingsMenu->SetOnTargetFpsChanged(
150 [this](uint32_t fps) { _graphics.SetTargetFPS(static_cast<int>(fps)); });
151
152 _settingsMenu->SetOnBack([this]() {
153 if (_settingsMenu) {
154 _settingsMenu->Hide();
155 }
156 if (_scene == Scene::MENU) {
157 if (_mainMenu) {
158 _mainMenu->Show();
159 }
160 }
161 _settingsOverlay = false;
162 });
163
164 _settingsMenu->SetOnMainMenu([this]() {
165 // Return to main menu while in-game
166 LOG_INFO("[Rendering] Back to main menu - leaving room");
168 _settingsOverlay = false;
169
170 // Notify server that player is leaving the room
172
173 if (_settingsMenu) {
174 _settingsMenu->Hide();
177 _settingsMenu->Initialize();
178 } else {
179 _settingsMenu->RefreshVisuals();
180 }
181 }
182
183 if (_entityRenderer) {
184 _entityRenderer->clearBackground(); // Clear background when leaving game
185 _entityRenderer->clearAllEntities();
186 }
187 _entityRenderer.reset();
188
189 if (_mainMenu) {
190 _mainMenu->Show();
191 }
192 });
193
194 _settingsMenu->SetOnAccessibility([this]() {
195 if (_settingsMenu) {
196 _settingsMenu->Hide();
197 }
198 if (_accessibilityMenu) {
199 _accessibilityMenu->Show();
200 }
201 });
202
203 _settingsMenu->Initialize();
204 _settingsMenu->Hide();
205}
206
208 _accessibilityMenu = std::make_unique<Game::AccessibilityMenu>(*_uiFactory, _graphics);
210
211 // Colorblind filter changed
212 _accessibilityMenu->SetOnColorblindFilterChanged([this](auto filter) {
213 LOG_INFO("[Rendering] Applying colorblind filter: ", static_cast<int>(filter));
214 // Map AccessibilityMenu filter to Graphics filter type
216 switch (filter) {
219 break;
222 break;
225 break;
228 break;
229 default:
231 break;
232 }
233 _graphics.SetColorblindFilter(graphicsFilter);
235 });
236
237 // Game speed changed
238 _accessibilityMenu->SetOnGameSpeedChanged([this](float speed) {
239 LOG_INFO("[Rendering] Game speed changed to: ", static_cast<int>(speed * 100), "%");
240 // TODO: Apply speed multiplier to game logic delta time
241 // This should be propagated to the GameLoop to adjust the fixed timestep
242 // For now, we just log it
243 });
244
245 // Key bindings configuration requested
246 _accessibilityMenu->SetOnConfigureKeyBindings([this]() {
247 LOG_INFO("[Rendering] Opening key bindings configuration");
248 if (_accessibilityMenu) {
249 _accessibilityMenu->Hide();
250 }
251 if (_keyBindingsMenu) {
253 _keyBindingsMenu->Initialize();
254 _keyBindingsMenu->Show();
255 _keyBindingsOverlay = true;
256 }
257 });
258
259 // Back button - return to settings menu
260 _accessibilityMenu->SetOnBack([this]() {
261 if (_accessibilityMenu) {
262 _accessibilityMenu->Hide();
263 }
264 if (_settingsMenu) {
265 _settingsMenu->Show();
266 }
267 });
268
269 _accessibilityMenu->Initialize();
270 _accessibilityMenu->Hide();
271}
272
274 _keyBindingsMenu = std::make_unique<Game::KeyBindingsMenu>(*_uiFactory, _graphics);
276
277 // Back button - return to accessibility menu
278 _keyBindingsMenu->SetOnBack([this]() {
279 if (_keyBindingsMenu) {
280 _keyBindingsMenu->Hide();
281 _keyBindingsOverlay = false;
282 }
283 if (_accessibilityMenu) {
284 _accessibilityMenu->Show();
285 }
286 });
287
288 // Bindings changed - save to file
289 _keyBindingsMenu->SetOnBindingsChanged([this]() {
290 LOG_INFO("[Rendering] Key bindings changed, saving...");
291 Input::KeyBindings::getInstance().SaveToFile("keybindings.cfg");
292 });
293
294 _keyBindingsMenu->Initialize();
295 _keyBindingsMenu->Hide();
296}
297
299 _mainMenu = std::make_unique<Game::MainMenu>(*_uiFactory);
300 _mainMenu->SetSoundEffectService(_soundEffectManager.get());
301
302 _mainMenu->SetOnPlay([this]() {
303 if (_mainMenu)
304 _mainMenu->Hide();
305
306 // Check if auto-matchmaking is enabled
307 bool autoMatchmaking = _settingsMenu && _settingsMenu->GetAutoMatchmaking();
308
309 if (autoMatchmaking) {
310 // Auto-matchmaking: directly request server to find/create room
311 LOG_INFO("[Rendering] Auto-matchmaking enabled, sending auto-matchmaking request");
313
314 // Show waiting room immediately (will be updated when joined)
316 _waitingRoomMenu->Show();
317 } else {
318 // Manual: show room selection menu
319 if (_roomListMenu)
320 _roomListMenu->Show();
321
322 // Request room list from server
324 }
325 });
326
327 _mainMenu->SetOnQuit([this]() { _quitRequested = true; });
328
329 _mainMenu->SetOnSettings([this]() {
330 if (_mainMenu) {
331 _mainMenu->Hide();
332 }
333 if (_settingsMenu) {
335 _settingsMenu->Show();
336 }
337 _settingsOverlay = false;
338 });
339
340 _mainMenu->SetOnProfile([this]() {
341 if (_mainMenu)
342 _mainMenu->Hide();
343 if (_loginMenu)
344 _loginMenu->Show();
345 _loginOverlay = true;
346 });
347
348 _mainMenu->SetOnSelectServer([this]() {
349 if (_mainMenu)
350 _mainMenu->Hide();
351 if (_serverListMenu)
352 _serverListMenu->Show();
353 });
354
355 // Pass screen dimensions for responsive layout (profile button)
356 _mainMenu->SetScreenSize(static_cast<float>(_width), static_cast<float>(_height));
357
358 _mainMenu->Initialize();
359 _mainMenu->Hide(); // Start hidden, show after server selection
360}
361
363 _loginMenu = std::make_unique<Game::LoginMenu>(*_uiFactory, _graphics);
364 _loginMenu->SetSoundEffectService(_soundEffectManager.get());
365
366 _loginMenu->SetOnBack([this]() {
367 if (_loginMenu)
368 _loginMenu->Hide();
369 if (_mainMenu)
370 _mainMenu->Show();
371 _loginOverlay = false;
372 });
373
374 _loginMenu->Initialize();
375 _loginMenu->Hide();
376}
377
379 _serverListMenu = std::make_unique<Game::ServerListMenu>(*_uiFactory, _graphics);
380 _serverListMenu->SetSoundEffectService(_soundEffectManager.get());
381
382 _serverListMenu->SetOnBack([this]() {
383 // Back from server selection = quit game
384 _quitRequested = true;
385 });
386
387 _serverListMenu->SetOnServerSelected([this](const std::string &ip, uint16_t port) {
388 // Get server name for display
389 _connectingServerName = "Unknown";
390 for (const auto &server : _serverListMenu->GetServers()) {
391 if (server.ip == ip && server.port == port) {
393 break;
394 }
395 }
396
397 // Store the selected server info
399 _selectedServerPort = port;
400 LOG_INFO("[Rendering] Connecting to server: ", ip, ":", port, "...");
401
402 // Set connecting state in ServerListMenu
403 if (_serverListMenu)
404 _serverListMenu->SetConnecting(true, _connectingServerName);
405
406 // Set connecting state
407 _isConnecting = true;
408
409 // Publish Server Connect event to trigger connection (async)
410 std::string serverInfo = ip + ":" + std::to_string(port);
412
413 // Don't block here - let the CONNECTION_FAILED or connection success handle UI updates
414 });
415
416 _serverListMenu->SetOnAddServer([this]() {
417 if (_serverListMenu)
418 _serverListMenu->Hide();
419 if (_addServerMenu)
420 _addServerMenu->Show();
421 });
422
423 _serverListMenu->Initialize();
424 _serverListMenu->Show(); // Show at startup
425}
426
428 _addServerMenu = std::make_unique<Game::AddServerMenu>(*_uiFactory, _graphics);
429 _addServerMenu->SetSoundEffectService(_soundEffectManager.get());
430
431 _addServerMenu->SetOnCancel([this]() {
432 if (_addServerMenu)
433 _addServerMenu->Hide();
434 if (_serverListMenu)
435 _serverListMenu->Show();
436 });
437
438 _addServerMenu->SetOnAdd([this](const std::string &name, const std::string &ip, const std::string &port) {
439 LOG_INFO("[Rendering] Adding server: ", name, " - ", ip, ":", port);
440
441 // Add server to list
442 if (_serverListMenu) {
443 try {
444 uint16_t portNum = static_cast<uint16_t>(std::stoi(port));
445 _serverListMenu->AddServer(name, ip, portNum);
446 } catch (...) {
447 LOG_ERROR("[Rendering] Failed to parse port: ", port);
448 }
449 }
450
451 // Hide add server menu and show server list
452 if (_addServerMenu)
453 _addServerMenu->Hide();
454 if (_serverListMenu)
455 _serverListMenu->Show();
456 });
457
458 _addServerMenu->Initialize();
459 _addServerMenu->Hide();
460}
461
463 _connectionMenu = std::make_unique<Game::ConnectionMenu>(*_uiFactory, _graphics);
464 _connectionMenu->SetSoundEffectService(_soundEffectManager.get());
465
466 _connectionMenu->SetOnBack([this]() {
467 if (_connectionMenu)
468 _connectionMenu->Hide();
469 if (_mainMenu)
470 _mainMenu->Show();
471 });
472
473 _connectionMenu->SetOnJoin(
474 [this](const std::string &nickname, const std::string &ip, const std::string &port) {
475 (void)nickname;
476 (void)ip;
477 (void)port;
478
479 // Publish Join Game event
481
482 if (_connectionMenu)
483 _connectionMenu->Hide();
484 StartGame();
485 });
486
487 _connectionMenu->Initialize();
488 _connectionMenu->Hide();
489}
490
492 _defeatMenu = std::make_unique<Game::DefeatMenu>(*_uiFactory);
493 _defeatMenu->SetSoundEffectService(_soundEffectManager.get());
494
495 _defeatMenu->SetOnReturnToMenu([this]() {
496 // Return to main menu
497 if (_defeatMenu)
498 _defeatMenu->Hide();
499 if (_mainMenu)
500 _mainMenu->Show();
502
503 // Publish event to leave the room
505 });
506
507 _defeatMenu->Initialize();
508 _defeatMenu->Hide();
509}
510
512 _victoryMenu = std::make_unique<Game::VictoryMenu>(*_uiFactory);
513 _victoryMenu->SetSoundEffectService(_soundEffectManager.get());
514
515 _victoryMenu->SetOnReturnToMenu([this]() {
516 // Return to main menu
517 if (_victoryMenu)
518 _victoryMenu->Hide();
519 if (_mainMenu)
520 _mainMenu->Show();
522
523 // Publish event to leave the room
525 });
526
527 _victoryMenu->Initialize();
528 _victoryMenu->Hide();
529}
530
532 _roomListMenu = std::make_unique<Game::RoomListMenu>(*_uiFactory, _graphics);
533 _roomListMenu->SetSoundEffectService(_soundEffectManager.get());
534
535 _roomListMenu->SetOnRoomSelected([this](const std::string &roomId) {
536 LOG_INFO("[Rendering] Room selected: ", roomId);
537 _selectedRoomId = roomId;
538
539 // Hide room list and show waiting room
540 if (_roomListMenu)
541 _roomListMenu->Hide();
543 _waitingRoomMenu->Show();
544
545 // Send JOIN_GAME event with room ID (but don't start game yet)
547 });
548
549 _roomListMenu->SetOnCreateRoom([this]() {
550 if (_roomListMenu)
551 _roomListMenu->Hide();
552 if (_createRoomMenu)
553 _createRoomMenu->Show();
554 });
555
556 _roomListMenu->SetOnBack([this]() {
557 if (_roomListMenu)
558 _roomListMenu->Hide();
559 if (_mainMenu)
560 _mainMenu->Show();
561 });
562
563 _roomListMenu->Initialize();
564 _roomListMenu->Hide();
565}
566
568 _createRoomMenu = std::make_unique<Game::CreateRoomMenu>(*_uiFactory, _graphics);
569 _createRoomMenu->SetSoundEffectService(_soundEffectManager.get());
570
571 _createRoomMenu->SetOnCreate(
572 [this](const std::string &roomName, uint32_t maxPlayers, bool isPrivate, float gameSpeedMultiplier) {
573 LOG_INFO("[Rendering] Creating room: ", roomName, " (Max: ", maxPlayers, ", Private: ", isPrivate,
574 ", Speed: ", static_cast<int>(gameSpeedMultiplier * 100), "%)");
575
576 // Publish CREATE_ROOM event (format: "roomName|maxPlayers|isPrivate|gameSpeedMultiplier")
577 std::string roomData = roomName + "|" + std::to_string(maxPlayers) + "|" +
578 (isPrivate ? "1" : "0") + "|" + std::to_string(gameSpeedMultiplier);
580
581 if (_createRoomMenu)
582 _createRoomMenu->Hide();
583
584 // Show WaitingRoom instead of RoomListMenu (creator becomes host automatically)
586 _waitingRoomMenu->Show();
587 });
588
589 _createRoomMenu->SetOnCancel([this]() {
590 if (_createRoomMenu)
591 _createRoomMenu->Hide();
592 if (_roomListMenu)
593 _roomListMenu->Show();
594 });
595
596 _createRoomMenu->Initialize();
597 _createRoomMenu->Hide();
598}
599
601 _waitingRoomMenu = std::make_unique<Game::WaitingRoomMenu>(*_uiFactory, _graphics);
602 _waitingRoomMenu->SetSoundEffectService(_soundEffectManager.get());
603
604 _waitingRoomMenu->SetOnStartGame([this]() {
605 LOG_INFO("[Rendering] Start Game button clicked");
606 // Publish START_GAME_REQUEST event
608 });
609
610 _waitingRoomMenu->SetOnBack([this]() {
611 LOG_INFO("[Rendering] Back to room list - leaving room");
613 _waitingRoomMenu->Hide();
614
615 // Notify server that player is leaving the room
617
618 if (_roomListMenu)
619 _roomListMenu->Show();
620 });
621
622 _waitingRoomMenu->Initialize();
623 _waitingRoomMenu->Hide();
624}
625
627 _eventBus.subscribe<UIEvent>([this](const UIEvent &event) {
628 if (event.getType() == UIEventType::AUTH_SUCCESS) {
629 // Update player name after authentication
630 const std::string &username = event.getData();
631 SetPlayerName(username);
632
633 // Hide both login and server list menus, show main menu
634 if (_loginMenu)
635 _loginMenu->Hide();
636 if (_serverListMenu)
637 _serverListMenu->Hide();
638 if (_mainMenu)
639 _mainMenu->Show();
640
641 LOG_INFO("[Rendering] Authentication successful, returning to main menu");
642 } else if (event.getType() == UIEventType::APPLY_AUTO_MATCHMAKING_PREF) {
643 // Apply auto-matchmaking preference from server
644 if (_settingsMenu) {
645 bool enabled = (event.getData() == "1");
646 _settingsMenu->ApplyAutoMatchmakingPreference(enabled);
647 LOG_INFO("[Rendering] Applied auto-matchmaking preference from server: ",
648 enabled ? "ON" : "OFF");
649 LOG_INFO("[Rendering] Matchmaking will only trigger when player clicks PLAY button");
650 }
651 } else if (event.getType() == UIEventType::CONNECTION_SUCCESS) {
652 LOG_INFO("[Rendering] Connection successful!");
653
654 // Clear connecting state
655 _isConnecting = false;
656 if (_serverListMenu)
657 _serverListMenu->SetConnecting(false);
658
659 // Request room list from server
661
662 // Hide server list and show main menu (room selection happens on PLAY click)
663 if (_serverListMenu)
664 _serverListMenu->Hide();
665 if (_mainMenu)
666 _mainMenu->Show();
667
668 } else if (event.getType() == UIEventType::CONNECTION_FAILED) {
669 LOG_ERROR("[Rendering] Connection failed: ", event.getData());
670
671 // Clear connecting state
672 _isConnecting = false;
673 if (_serverListMenu)
674 _serverListMenu->SetConnecting(false);
675
676 // Set error message in server list (it's already visible)
677 if (_serverListMenu) {
678 _serverListMenu->SetConnectionError("Connection failed: Server unreachable");
679 }
680
681 // Make sure we're back to menu scene
683 } else if (event.getType() == UIEventType::ROOM_LIST_RECEIVED) {
684 LOG_INFO("[Rendering] Room list received");
685 // Room list will be updated by GameLoop parsing the network message
686 } else if (event.getType() == UIEventType::REGISTER_SUCCESS) {
687 LOG_INFO("[Rendering] Registration successful: ", event.getData());
688 if (_loginMenu) {
689 _loginMenu->SetSuccessMessage("Registration successful! You can now login.");
690 }
691 } else if (event.getType() == UIEventType::REGISTER_FAILED) {
692 LOG_ERROR("[Rendering] Registration failed: ", event.getData());
693 if (_loginMenu) {
694 _loginMenu->SetErrorMessage(event.getData());
695 }
696 } else if (event.getType() == UIEventType::LOGIN_FAILED) {
697 LOG_ERROR("[Rendering] Login failed: ", event.getData());
698 if (_loginMenu) {
699 _loginMenu->SetErrorMessage(event.getData());
700 }
701 }
702 });
703}
704
705// ===== End of Menu Initialization Functions =====
706
708 if (!_initialized) {
709 return;
710 }
712 _initialized = false;
713}
714
716 if (!_initialized) {
717 return;
718 }
719
720 // Kept for legacy callers; main loop uses Render() which clears.
722}
723
724void Rendering::SetShowPing(bool enabled) {
725 _showPing = enabled;
726}
727
729 return _showPing;
730}
731
732void Rendering::SetShowFps(bool enabled) {
733 _showFps = enabled;
734}
735
737 return _showFps;
738}
739
740void Rendering::SetPlayerName(const std::string &name) {
741 if (_mainMenu) {
742 _mainMenu->SetProfileName(name);
743 }
744 LOG_INFO("[Rendering] Player name updated to: ", name);
745}
746
748 if (!_initialized)
749 return;
750
751 LOG_INFO("Rendering: Force switching to Game Scene");
753
754 // Hide all menus
755 if (_mainMenu)
756 _mainMenu->Hide();
757 if (_serverListMenu)
758 _serverListMenu->Hide();
759 if (_addServerMenu)
760 _addServerMenu->Hide();
761 if (_roomListMenu)
762 _roomListMenu->Hide();
763 if (_createRoomMenu)
764 _createRoomMenu->Hide();
766 _waitingRoomMenu->Hide();
767 if (_connectionMenu)
768 _connectionMenu->Hide();
769 if (_settingsMenu)
770 _settingsMenu->Hide();
771
772 _settingsOverlay = false;
773
774 // Enable entity renderer
775 if (!_entityRenderer) {
776 _entityRenderer = std::make_unique<EntityRenderer>(_graphics);
777 }
778}
779
780void Rendering::ShowGameOver(const std::string &reason) {
782 _gameOverReason = reason;
783
784 // Check if it's a victory or defeat
785 bool isVictory = (reason.find("Victory") != std::string::npos) ||
786 (reason.find("victory") != std::string::npos) ||
787 (reason.find("Win") != std::string::npos) || (reason.find("win") != std::string::npos);
788
789 // Hide all other menus and show the appropriate game over menu
790 if (_defeatMenu)
791 _defeatMenu->Hide();
792 if (_victoryMenu)
793 _victoryMenu->Hide();
795 _settingsMenu->Hide();
796 _settingsOverlay = false;
797 }
798
799 if (isVictory && _victoryMenu) {
800 _victoryMenu->SetVictoryMessage(reason);
801 _victoryMenu->Show();
802 } else if (_defeatMenu) {
803 _defeatMenu->SetDefeatReason(reason);
804 _defeatMenu->Show();
805 }
806}
807
809 if (!_initialized) {
810 return;
811 }
812
814
815 if (_quitRequested) {
816 _initialized = false;
817 return;
818 }
819
821 UpdateUI();
822
825
826 // Begin colorblind capture if filter is active
828
830 RenderUI();
831 RenderHUD();
832
833 // End colorblind capture and apply filter
835
837
838 // Check if user wants to close the window and stop the game loop
840 // Trigger game loop shutdown
841 // This will be detected by the GameLoop and initiate clean shutdown
842 }
843}
844
846 const float dt = _graphics.GetDeltaTime();
847 _fpsAccumulator += dt;
848 _fpsFrameCount += 1;
849 if (_fpsAccumulator >= 1.0f) {
851 _fpsFrameCount = 0;
852 _fpsAccumulator = 0.0f;
853 }
854}
855
857 // Pause menu toggle only in-game using configurable binding
858 auto &bindings = Input::KeyBindings::getInstance();
859 int pauseKey = bindings.GetPrimaryKey(Input::GameAction::PAUSE_MENU);
860 int pauseKeyAlt = bindings.GetSecondaryKey(Input::GameAction::PAUSE_MENU);
861
862 bool pausePressed = (pauseKey != KEY_NULL && _graphics.IsKeyPressed(pauseKey)) ||
863 (pauseKeyAlt != KEY_NULL && _graphics.IsKeyPressed(pauseKeyAlt));
864
865 if (_scene != Scene::IN_GAME || !pausePressed || !_settingsMenu) {
866 return;
867 }
868
869 if (_settingsMenu->IsVisible() && _settingsOverlay) {
870 _settingsMenu->Hide();
871 _settingsOverlay = false;
872 } else {
873 // Only rebuild menu if the mode actually changes (button count differs)
876 _settingsMenu->Initialize();
877 } else {
878 _settingsMenu->RefreshVisuals();
879 }
880 _settingsMenu->Show();
881 _settingsOverlay = true;
882 }
883}
884
886 // Update chat visibility based on scene
888
889 // Update chat widget
890 if (_chatWidget && _chatWidget->IsVisible()) {
891 _chatWidget->Update();
892 }
893
894 if (_confirmQuitMenu && _confirmQuitMenu->IsVisible()) {
895 _confirmQuitMenu->Update();
896 return;
897 }
898
899 if (_scene == Scene::MENU) {
900 if (_mainMenu && _mainMenu->IsVisible()) {
901 _mainMenu->Update();
902 }
903 if (_serverListMenu && _serverListMenu->IsVisible()) {
904 _serverListMenu->Update();
905 }
906 if (_addServerMenu && _addServerMenu->IsVisible()) {
907 _addServerMenu->Update();
908 }
909 if (_roomListMenu && _roomListMenu->IsVisible()) {
910 _roomListMenu->Update();
911 }
912 if (_createRoomMenu && _createRoomMenu->IsVisible()) {
913 _createRoomMenu->Update();
914 }
915 if (_waitingRoomMenu && _waitingRoomMenu->IsVisible()) {
916 _waitingRoomMenu->Update();
917 }
918 if (_connectionMenu && _connectionMenu->IsVisible()) {
919 _connectionMenu->Update();
920 }
921 if (_settingsMenu && _settingsMenu->IsVisible()) {
922 _settingsMenu->Update();
923 }
924 if (_accessibilityMenu && _accessibilityMenu->IsVisible()) {
925 _accessibilityMenu->Update();
926 }
927 if (_keyBindingsMenu && _keyBindingsMenu->IsVisible()) {
928 _keyBindingsMenu->Update();
929 }
930 if (_loginMenu && _loginMenu->IsVisible()) {
931 _loginMenu->Update();
932
933 // Check for submission
934 if (_loginMenu->IsRegisterSubmitted()) {
935 // Register: Send RegisterAccount event
936 std::string username = _loginMenu->GetUsername();
937 std::string password = _loginMenu->GetPassword();
938
939 if (!username.empty() && !password.empty()) {
940 LOG_INFO("[Rendering] Sending register request for user: " + username);
941 // Publish event with "username:password" format
942 std::string credentials = username + ":" + password;
944
945 // Reset the menu state so it doesn't keep sending
946 _loginMenu->Reset();
947 } else {
948 _loginMenu->SetErrorMessage("Please enter username and password");
949 }
950
951 } else if (_loginMenu->IsLoginSubmitted()) {
952 // Login: Send LoginAccount event
953 std::string username = _loginMenu->GetUsername();
954 std::string password = _loginMenu->GetPassword();
955
956 if (!username.empty() && !password.empty()) {
957 LOG_INFO("[Rendering] Sending login request for user: " + username);
958 // Publish event with "username:password" format
959 std::string credentials = username + ":" + password;
961
962 // Reset the menu state so it doesn't keep sending
963 _loginMenu->Reset();
964 } else {
965 _loginMenu->SetErrorMessage("Please enter username and password");
966 }
967
968 } else if (_loginMenu->IsGuestSubmitted()) {
969 // Guest login: send guest credentials to re-authenticate as guest
970 LOG_INFO("[Rendering] Guest login selected - sending guest credentials");
971
972 // Send guest credentials
973 std::string credentials = "guest:guest";
975
976 // Reset the menu state
977 _loginMenu->Reset();
978 }
979 }
980 } else {
981 // In-game: only overlay settings gets updates
982 if (_settingsMenu && _settingsMenu->IsVisible() && _settingsOverlay) {
983 _settingsMenu->Update();
984 }
985 if (_accessibilityMenu && _accessibilityMenu->IsVisible()) {
986 _accessibilityMenu->Update();
987 }
988 if (_keyBindingsMenu && _keyBindingsMenu->IsVisible()) {
989 _keyBindingsMenu->Update();
990 }
991 }
992
993 // Game over scene: update defeat/victory menus
994 if (_scene == Scene::GAME_OVER) {
995 if (_defeatMenu && _defeatMenu->IsVisible()) {
996 _defeatMenu->Update();
997 }
998 if (_victoryMenu && _victoryMenu->IsVisible()) {
999 _victoryMenu->Update();
1000 }
1001 }
1002}
1003
1006 // Update background scroll before rendering
1007 _entityRenderer->updateBackground(_graphics.GetDeltaTime());
1008 _entityRenderer->render();
1009 }
1010}
1011
1013 if (_confirmQuitMenu && _confirmQuitMenu->IsVisible()) {
1014 if (_confirmQuitOverlay) {
1015 _graphics.DrawRectFilled(0, 0, static_cast<int>(_width), static_cast<int>(_height), 0x88000000);
1016 }
1017 _confirmQuitMenu->Render();
1018 return;
1019 }
1020
1021 if (_scene == Scene::MENU) {
1022 if (_mainMenu && _mainMenu->IsVisible()) {
1023 _mainMenu->Render();
1024 }
1025 if (_serverListMenu && _serverListMenu->IsVisible()) {
1026 _serverListMenu->Render();
1027 }
1028 if (_addServerMenu && _addServerMenu->IsVisible()) {
1029 _addServerMenu->Render();
1030 }
1031 if (_roomListMenu && _roomListMenu->IsVisible()) {
1032 _roomListMenu->Render();
1033 }
1034 if (_createRoomMenu && _createRoomMenu->IsVisible()) {
1035 _createRoomMenu->Render();
1036 }
1037 if (_waitingRoomMenu && _waitingRoomMenu->IsVisible()) {
1038 _waitingRoomMenu->Render();
1039 }
1040 if (_connectionMenu && _connectionMenu->IsVisible()) {
1041 _connectionMenu->Render();
1042 }
1043 if (_settingsMenu && _settingsMenu->IsVisible()) {
1044 _settingsMenu->Render();
1045 }
1046 if (_accessibilityMenu && _accessibilityMenu->IsVisible()) {
1047 _accessibilityMenu->Render();
1048 }
1049 if (_keyBindingsMenu && _keyBindingsMenu->IsVisible()) {
1050 _keyBindingsMenu->Render();
1051 }
1052 if (_loginMenu && _loginMenu->IsVisible()) {
1053 _loginMenu->Render();
1054 }
1055 } else {
1056 if (_settingsMenu && _settingsMenu->IsVisible() && _settingsOverlay) {
1057 if (_settingsMenu->ShouldDimBackground()) {
1058 _graphics.DrawRectFilled(0, 0, static_cast<int>(_width), static_cast<int>(_height),
1059 _settingsMenu->GetOverlayDimColor());
1060 }
1061 _settingsMenu->Render();
1062 }
1063 if (_accessibilityMenu && _accessibilityMenu->IsVisible()) {
1064 if (_accessibilityMenu->ShouldDimBackground()) {
1065 _graphics.DrawRectFilled(0, 0, static_cast<int>(_width), static_cast<int>(_height),
1066 _accessibilityMenu->GetOverlayDimColor());
1067 }
1068 _accessibilityMenu->Render();
1069 }
1070 if (_keyBindingsMenu && _keyBindingsMenu->IsVisible()) {
1071 if (_keyBindingsMenu->ShouldDimBackground()) {
1072 _graphics.DrawRectFilled(0, 0, static_cast<int>(_width), static_cast<int>(_height),
1073 _keyBindingsMenu->GetOverlayDimColor());
1074 }
1075 _keyBindingsMenu->Render();
1076 }
1077 }
1078
1079 // Game over scene: render defeat/victory menus
1080 if (_scene == Scene::GAME_OVER) {
1081 // Draw dim background
1082 _graphics.DrawRectFilled(0, 0, static_cast<int>(_width), static_cast<int>(_height), 0xCC000000);
1083
1084 // Draw large game over text
1085 int screenCenterX = static_cast<int>(_width) / 2;
1086 int screenCenterY = static_cast<int>(_height) / 2;
1087 int fontSize = 72;
1088
1089 if (_victoryMenu && _victoryMenu->IsVisible()) {
1090 // Draw victory text in green/gold
1091 int textWidth = static_cast<int>(_gameOverReason.length() * fontSize * 0.6);
1092 int textX = screenCenterX - textWidth / 2;
1093 _graphics.DrawText(_gameOverReason.c_str(), textX, screenCenterY - 150, fontSize, 0xFFFFD700);
1094 _victoryMenu->Render();
1095 } else if (_defeatMenu && _defeatMenu->IsVisible()) {
1096 // Draw defeat text in red
1097 int textWidth = static_cast<int>(_gameOverReason.length() * fontSize * 0.6);
1098 int textX = screenCenterX - textWidth / 2;
1099 _graphics.DrawText(_gameOverReason.c_str(), textX, screenCenterY - 150, fontSize, 0xFFFF4444);
1100 _defeatMenu->Render();
1101 }
1102 }
1103
1104 // Render chat widget (on top of everything)
1105 if (_chatWidget && _chatWidget->IsVisible()) {
1106 _chatWidget->Render();
1107 }
1108}
1109
1111 const int fontSize = 20;
1112 const int margin = 10;
1113 const int pad = 6;
1114
1115 // Ping (top-right)
1116 int hudRightX = _graphics.GetWindowWidth() - margin;
1117 int hudY = margin;
1118
1119 if (_showPing) {
1120 const bool hasMeasurement = (_displayedPing != 0);
1121 const std::string pingText =
1122 hasMeasurement ? ("PING: " + std::to_string(_displayedPing) + " ms") : std::string("PING: --");
1123
1124 const int textWidth = UI::TextUtils::EstimateTextWidth(pingText, fontSize);
1125 const int x = hudRightX - textWidth;
1126 const int y = hudY;
1127
1128 _graphics.DrawRectFilled(x - pad, y - pad, textWidth + pad * 2, fontSize + pad * 2, 0x88000000);
1129 _graphics.DrawText(-1, pingText.c_str(), x, y, fontSize, 0xFFFFFFFF);
1130
1131 hudY += fontSize + pad * 2 + 6;
1132 }
1133
1134 // FPS (below ping, top-right)
1135 if (_showFps) {
1136 const std::string fpsText = "FPS: " + std::to_string(_fps);
1137 const int textWidth = UI::TextUtils::EstimateTextWidth(fpsText, fontSize);
1138 const int x = hudRightX - textWidth;
1139 const int y = hudY;
1140
1141 _graphics.DrawRectFilled(x - pad, y - pad, textWidth + pad * 2, fontSize + pad * 2, 0x88000000);
1142 _graphics.DrawText(-1, fpsText.c_str(), x, y, fontSize, 0xFFFFFFFF);
1143 }
1144}
1145
1147 if (!_initialized) {
1148 return false;
1149 }
1151}
1152
1153bool Rendering::LoadTexture(const std::string &textureName, const std::string &path) {
1154 int result = _graphics.LoadTexture(textureName.c_str(), path.c_str());
1155 return result != -1;
1156}
1157
1158void Rendering::DrawSprite(const std::string &textureId, float xPosition, float yPosition, float rotation,
1159 float scale) {
1160 _graphics.DrawTextureEx(textureId.c_str(), 0, 0, 0, 0, xPosition, yPosition, rotation, scale, 0xFFFFFFFF);
1161}
1162
1163void Rendering::DrawText(const std::string &text, float xPosition, float yPosition, uint32_t size) {
1164 _graphics.DrawText(-1, text.c_str(), static_cast<int>(xPosition), static_cast<int>(yPosition),
1165 static_cast<int>(size), 0xFFFFFFFF);
1166}
1167
1168uint32_t Rendering::GetWidth() const {
1169 return _width;
1170}
1171
1172uint32_t Rendering::GetHeight() const {
1173 return _height;
1174}
1175
1177 if (!_initialized) {
1178 return false;
1179 }
1181}
1182
1183// ═══════════════════════════════════════════════════════════
1184// Entity Rendering API (delegation to EntityRenderer)
1185// ═══════════════════════════════════════════════════════════
1186
1187void Rendering::UpdateEntity(uint32_t id, RType::Messages::Shared::EntityType type, float x, float y,
1188 int health, const std::string &currentAnimation, int srcX, int srcY, int srcW,
1189 int srcH) {
1190 if (_entityRenderer) {
1191 _entityRenderer->updateEntity(id, type, x, y, health, currentAnimation, srcX, srcY, srcW, srcH);
1192 }
1193}
1194
1195void Rendering::RemoveEntity(uint32_t id) {
1196 if (_entityRenderer) {
1197 _entityRenderer->removeEntity(id);
1198 }
1199}
1200
1201void Rendering::SetMyEntityId(uint32_t id) {
1202 if (_entityRenderer) {
1203 _entityRenderer->setMyEntityId(id);
1204 }
1205}
1206
1208 if (_entityRenderer) {
1209 _entityRenderer->clearAllEntities();
1210 }
1211}
1212
1213void Rendering::SetBackground(const std::string &mainBackground, const std::string &parallaxBackground,
1214 float scrollSpeed, float parallaxSpeedFactor) {
1215 if (_entityRenderer) {
1216 _entityRenderer->setBackground(mainBackground, parallaxBackground, scrollSpeed, parallaxSpeedFactor);
1217 }
1218}
1219
1221 if (_entityRenderer) {
1222 _entityRenderer->clearBackground();
1223 }
1224}
1225
1226void Rendering::UpdateBackground(float deltaTime) {
1227 if (_entityRenderer) {
1228 _entityRenderer->updateBackground(deltaTime);
1229 }
1230}
1231
1232bool Rendering::IsKeyDown(int key) const {
1233 return _graphics.IsKeyDown(key);
1234}
1235
1236bool Rendering::IsGamepadAvailable(int gamepad) const {
1237 return _graphics.IsGamepadAvailable(gamepad);
1238}
1239
1240bool Rendering::IsGamepadButtonDown(int gamepad, int button) const {
1241 return _graphics.IsGamepadButtonDown(gamepad, button);
1242}
1243
1244void Rendering::UpdateInterpolation(float deltaTime) {
1245 if (_entityRenderer) {
1246 _entityRenderer->updateInterpolation(deltaTime);
1247 }
1248}
1249
1250void Rendering::UpdatePingTimer(float deltaTime) {
1251 _pingUpdateTimer += deltaTime;
1252
1253 // Update displayed ping once per second
1256 _pingUpdateTimer = 0.0f;
1257 }
1258}
1259
1260void Rendering::MoveEntityLocally(uint32_t entityId, float deltaX, float deltaY) {
1261 if (_entityRenderer) {
1262 _entityRenderer->moveEntityLocally(entityId, deltaX, deltaY);
1263 }
1264}
1265
1267 if (_entityRenderer) {
1268 _entityRenderer->setClientSidePredictionEnabled(enabled);
1269 }
1270}
1271
1273 if (_entityRenderer) {
1274 _entityRenderer->setReconciliationThreshold(threshold);
1275 }
1276}
1277
1279 if (_entityRenderer) {
1280 return _entityRenderer->getReconciliationThreshold();
1281 }
1282 return 5.0f; // Default value
1283}
1284
1286 if (_entityRenderer) {
1287 _entityRenderer->setLocalPlayerMoving(moving);
1288 }
1289}
1290
1291void Rendering::SetPing(uint32_t pingMs) {
1292 _currentPing = pingMs;
1293}
1294
1295void Rendering::UpdateRoomList(const std::vector<RoomData> &rooms) {
1296 if (!_roomListMenu) {
1297 return;
1298 }
1299
1300 std::vector<Game::RoomListMenu::RoomInfo> roomInfos;
1301 for (const auto &room : rooms) {
1302 roomInfos.emplace_back(room.roomId, room.roomName, room.playerCount, room.maxPlayers, room.isPrivate,
1303 room.state);
1304 }
1305
1306 _roomListMenu->UpdateRoomList(roomInfos);
1307 LOG_INFO("[Rendering] Room list updated with ", rooms.size(), " rooms");
1308}
1309
1310void Rendering::UpdateWaitingRoom(const std::vector<Game::PlayerInfo> &players, const std::string &roomName,
1311 bool isHost, bool isSpectator) {
1312 if (!_waitingRoomMenu) {
1313 return;
1314 }
1315
1316 _waitingRoomMenu->UpdatePlayerList(players);
1317 _waitingRoomMenu->SetRoomInfo(roomName, static_cast<uint32_t>(players.size()),
1318 4); // TODO: get max from server
1319 _waitingRoomMenu->SetIsHost(isHost);
1320 _waitingRoomMenu->SetIsSpectator(isSpectator);
1321
1322 LOG_INFO("[Rendering] Waiting room updated with ", players.size(), " players, isHost=", isHost,
1323 ", isSpectator=", isSpectator);
1324}
1325
1327 if (!_uiFactory) {
1328 LOG_ERROR("[Rendering] Cannot initialize chat widget: UIFactory not initialized");
1329 return;
1330 }
1331
1332 _chatWidget = std::make_unique<Game::ChatWidget>(*_uiFactory, _graphics);
1333 _chatWidget->Initialize();
1334
1335 float x = _width - 300.0f;
1336 float y = _height - 240.0f;
1337
1338 _chatWidget->SetPosition(x, y);
1339 _chatWidget->SetVisible(false); // Will be set by UpdateChatVisibility
1340
1341 LOG_INFO("[Rendering] Chat widget initialized");
1342}
1343
1344void Rendering::AddChatMessage(uint32_t playerId, const std::string &playerName, const std::string &message,
1345 uint64_t timestamp) {
1346 if (_chatWidget) {
1347 _chatWidget->AddMessage(playerId, playerName, message, timestamp);
1348 }
1349}
1350
1351void Rendering::SetOnChatMessageSent(std::function<void(const std::string &)> callback) {
1352 if (_chatWidget) {
1353 _chatWidget->SetOnMessageSent(callback);
1354 }
1355}
1356
1358 if (!_chatWidget) {
1359 return;
1360 }
1361
1362 // Show chat in waiting room or in-game, but only if enabled in settings
1363 bool shouldBeVisible = (_scene == Scene::IN_GAME) || (_waitingRoomMenu && _waitingRoomMenu->IsVisible());
1364
1365 // Check if chat is enabled in settings
1366 if (_settingsMenu && !_settingsMenu->GetShowChat()) {
1367 shouldBeVisible = false;
1368 }
1369
1370 _chatWidget->SetVisible(shouldBeVisible);
1371}
1372
1375
1376 if (Settings::LoadSettings(settings)) {
1377 LOG_INFO("[Rendering] Loaded accessibility settings from ", Settings::SETTINGS_FILE_PATH);
1378 } else {
1379 LOG_INFO("[Rendering] No accessibility settings file found, using defaults");
1380 }
1381
1382 // Apply loaded settings to the accessibility menu (silently, no callbacks)
1383 if (_accessibilityMenu) {
1384 // Map ColorblindFilterType to AccessibilityMenu::ColorblindFilter
1386 switch (settings.colorblindFilter) {
1389 break;
1392 break;
1395 break;
1398 break;
1399 default:
1401 break;
1402 }
1403 _accessibilityMenu->SetColorblindFilterSilent(filter);
1404
1405 // Apply colorblind filter to graphics
1407 switch (settings.colorblindFilter) {
1410 break;
1413 break;
1416 break;
1419 break;
1420 default:
1421 graphicsFilter = Graphics::ColorblindFilterType::NONE;
1422 break;
1423 }
1424 _graphics.SetColorblindFilter(graphicsFilter);
1425 }
1426}
1427
1429 if (!_accessibilityMenu) {
1430 return;
1431 }
1432
1434 settings.SetDefaults();
1435
1436 // Get current settings from accessibility menu
1437 auto filter = _accessibilityMenu->GetColorblindFilter();
1438 switch (filter) {
1441 break;
1444 break;
1447 break;
1450 break;
1451 default:
1453 break;
1454 }
1455
1456 if (Settings::SaveSettings(settings)) {
1457 LOG_INFO("[Rendering] Saved accessibility settings to ", Settings::SETTINGS_FILE_PATH);
1458 } else {
1459 LOG_ERROR("[Rendering] Failed to save accessibility settings");
1460 }
1461}
#define LOG_INFO(...)
Definition Logger.hpp:181
#define LOG_ERROR(...)
Definition Logger.hpp:183
#define LOG_WARNING(...)
Definition Logger.hpp:182
@ APPLY_AUTO_MATCHMAKING_PREF
@ UPDATE_AUTO_MATCHMAKING_PREF
Type-safe event publication/subscription system.
Definition EventBus.hpp:44
void publish(const T &event)
Publish an event to all subscribers.
Definition EventBus.hpp:116
size_t subscribe(EventCallback< T > callback)
Subscribe to a specific event type.
Definition EventBus.hpp:108
ColorblindFilter
Colorblind filter types.
@ MONOCHROMACY
Complete color blindness.
@ FULLSCREEN
Takes the whole window (main menu context)
@ OVERLAY
Displays over the game with dimmed background.
@ OVERLAY
Displays over the game with a dimmed background.
@ FULLSCREEN
Takes the whole window (main menu context)
float GetDeltaTime() const override
Get the time elapsed for the last frame.
void DrawRectFilled(int x, int y, int width, int height, unsigned int color) override
Draw a filled rectangle.
void DisplayWindow() override
Display the current frame to the window (end drawing and swap buffers)
void DrawTextureEx(const char *textureName, int srcX, int srcY, int srcW, int srcH, float destX, float destY, float rotation, float scale, unsigned int tint) override
Draw a texture with advanced parameters (rotation, scale, source rectangle)
bool IsKeyPressed(int key) const override
Check if a key was pressed (triggered once when key goes down)
bool IsKeyDown(int key) const override
Check if a key is currently being held down.
void CloseWindow() override
Close the graphics window and cleanup resources.
bool WindowShouldClose() const override
Check if the window should close.
void SetTargetFPS(int fps) override
Set the target frames per second for rendering.
void BeginColorblindCapture() override
Begin capturing frame for colorblind filter processing.
void SetColorblindFilter(ColorblindFilterType filter) override
Set the colorblind filter type.
void StartDrawing() override
Begin drawing frame (setup canvas for drawing operations)
void ClearWindow() override
Clear the window with the current clear color.
bool IsGamepadAvailable(int gamepad) const override
Check if a gamepad is available/connected.
void DrawText(int fontHandle, const char *text, int x, int y, int fontSize, unsigned int color) override
Draw text using a loaded font.
bool IsWindowOpen() const override
Check if the window is still open.
int GetWindowWidth() const override
Get current window width in pixels.
void InitWindow(int width, int height, const char *title) override
Initialize the graphics window.
void EndColorblindCapture() override
End capturing and apply the colorblind filter.
bool IsGamepadButtonDown(int gamepad, int button) const override
Check if a gamepad button is currently held down.
int LoadTexture(const char *name, const char *filepath) override
Load a texture from an image file.
static KeyBindings & getInstance()
Get the singleton instance.
bool SaveToFile(const std::string &filepath) const
Save bindings to a file.
bool LoadFromFile(const std::string &filepath)
Load bindings from a file.
std::string _connectingServerName
std::unique_ptr< EntityRenderer > _entityRenderer
EventBus & _eventBus
uint32_t GetHeight() const
Get window height.
void UpdateEntity(uint32_t id, RType::Messages::Shared::EntityType type, float x, float y, int health, const std::string &currentAnimation, int srcX, int srcY, int srcW, int srcH)
Update or create an entity for rendering with animation.
Graphics::RaylibGraphics _graphics
std::string _selectedServerIp
uint32_t _fps
void ClearBackground()
Clear background configuration.
Rendering(EventBus &eventBus)
Constructor with EventBus reference.
Definition Rendering.cpp:15
std::unique_ptr< Game::SettingsMenu > _settingsMenu
void RenderHUD()
Render HUD elements (ping, FPS).
void ClearAllEntities()
Clear all entities from the rendering cache.
void MoveEntityLocally(uint32_t entityId, float deltaX, float deltaY)
Move an entity locally (client-side prediction)
void SetMyEntityId(uint32_t id)
Set the local player's entity ID.
void InitializeAccessibilityMenu()
bool GetShowPing() const
Get ping display state.
std::unique_ptr< Game::AccessibilityMenu > _accessibilityMenu
bool IsKeyDown(int key) const
Check if a key is currently being held down.
bool WindowShouldClose() const
void InitializeLoginMenu()
static constexpr float PING_UPDATE_INTERVAL
void InitializeServerListMenu()
void InitializeMenus()
Initialize UI factory, menus and all related callbacks.
Definition Rendering.cpp:56
uint32_t _currentPing
void InitializeVictoryMenu()
float _pingUpdateTimer
void SetOnChatMessageSent(std::function< void(const std::string &)> callback)
Set callback for when a chat message is sent.
void UpdateFpsCounter()
Update FPS counter based on delta time.
void UpdateRoomList(const std::vector< RoomData > &rooms)
Update room list from server data.
bool LoadTexture(const std::string &textureName, const std::string &path)
Load a texture from file.
bool _loginOverlay
void InitializeCreateRoomMenu()
void RemoveEntity(uint32_t id)
Remove an entity from rendering.
void SetBackground(const std::string &mainBackground, const std::string &parallaxBackground, float scrollSpeed, float parallaxSpeedFactor)
Set up background layers for parallax scrolling.
bool _showFps
std::unique_ptr< Game::RoomListMenu > _roomListMenu
std::string _gameOverReason
void SubscribeToConnectionEvents()
void SetShowPing(bool enabled)
Enable/disable ping display.
std::unique_ptr< UI::RaylibUIFactory > _uiFactory
void DrawText(const std::string &text, float xPosition, float yPosition, uint32_t size=24)
Draw text on screen.
void UpdateInterpolation(float deltaTime)
Update interpolation for all entities.
void InitializeMainMenu()
uint32_t _fpsFrameCount
std::unique_ptr< Game::ConnectionMenu > _connectionMenu
std::unique_ptr< Game::KeyBindingsMenu > _keyBindingsMenu
bool GetShowFps() const
Get FPS display state.
bool _settingsOverlay
bool _initialized
bool IsWindowOpen() const
Check if window is open.
void UpdateChatVisibility()
Update chat widget visibility based on current scene.
Scene _scene
void ApplyInitialMenuSettings()
Apply runtime settings affecting rendering (target FPS, HUD visibility...).
Definition Rendering.cpp:89
bool Initialize(uint32_t width, uint32_t height, const std::string &title)
Initialize the rendering system and create window.
Definition Rendering.cpp:25
void InitializeConfirmQuitMenu()
void InitializeRoomListMenu()
void RenderGameScene()
Render the game scene (entities).
std::unique_ptr< Game::CreateRoomMenu > _createRoomMenu
std::unique_ptr< Game::AddServerMenu > _addServerMenu
std::unique_ptr< Game::VictoryMenu > _victoryMenu
void SetLocalPlayerMoving(bool moving)
Set whether the local player is currently moving.
void InitializeConnectionMenu()
std::unique_ptr< Game::ConfirmQuitMenu > _confirmQuitMenu
std::unique_ptr< Game::LoginMenu > _loginMenu
~Rendering()
Destructor.
Definition Rendering.cpp:21
bool _quitRequested
std::unique_ptr< Game::DefeatMenu > _defeatMenu
void Render()
Perform rendering of current frame.
void SetReconciliationThreshold(float threshold)
Set the reconciliation threshold for client-side prediction.
bool _keyBindingsOverlay
void InitializeKeyBindingsMenu()
bool _showPing
void Shutdown()
Stop the rendering system and destroy window.
void UpdateUI()
Update all UI elements based on current scene.
void InitializeDefeatMenu()
void AddChatMessage(uint32_t playerId, const std::string &playerName, const std::string &message, uint64_t timestamp)
Add a chat message to the chat widget.
void ShowGameOver(const std::string &reason)
Display the game over screen.
uint32_t _width
void LoadAccessibilitySettings()
void SetPlayerName(const std::string &name)
Update the displayed player name (e.g., after authentication)
void InitializeSettingsMenu()
void ClearWindow()
Clears the window before rendering its content.
std::unique_ptr< Game::MainMenu > _mainMenu
uint32_t _displayedPing
uint32_t GetWidth() const
Get window width.
std::unique_ptr< Game::WaitingRoomMenu > _waitingRoomMenu
void SetClientSidePredictionEnabled(bool enabled)
Enable or disable client-side prediction for local player.
void UpdatePingTimer(float deltaTime)
Update ping display timer (called every frame)
std::unique_ptr< Game::ChatWidget > _chatWidget
void InitializeChatWidget()
uint16_t _selectedServerPort
void StartGame()
Switch immediately to the game scene.
void HandleEscapeKeyInput()
Handle ESC key input to toggle settings overlay in-game.
void UpdateBackground(float deltaTime)
Update background scroll positions.
void SetPing(uint32_t pingMs)
Set the current ping value for display.
void SaveAccessibilitySettings()
bool _isConnecting
void DrawSprite(const std::string &textureId, float xPosition, float yPosition, float rotation=0.0, float scale=1.0)
Draw a sprite on screen.
void InitializeAddServerMenu()
std::unique_ptr< Audio::SoundEffectManager > _soundEffectManager
void RenderUI()
Render all UI menus based on current scene and overlay state.
bool IsGamepadButtonDown(int gamepad, int button) const
Check if a gamepad button is currently held down.
bool _confirmQuitOverlay
void InitializeWaitingRoomMenu()
float GetReconciliationThreshold() const
Get the current reconciliation threshold.
float _fpsAccumulator
std::string _selectedRoomId
bool IsGamepadAvailable(int gamepad) const
Check if a gamepad is available/connected.
std::unique_ptr< Game::ServerListMenu > _serverListMenu
uint32_t _height
void UpdateWaitingRoom(const std::vector< Game::PlayerInfo > &players, const std::string &roomName, bool isHost, bool isSpectator=false)
Update waiting room with player list.
void SetShowFps(bool enabled)
Enable/disable FPS display.
ColorblindFilterType
Colorblind filter types for accessibility.
Definition IGraphics.hpp:15
@ DEUTERANOPIA
Green-blind (reduced green sensitivity)
@ PROTANOPIA
Red-blind (reduced red sensitivity)
@ MONOCHROMACY
Complete color blindness (grayscale)
@ TRITANOPIA
Blue-blind (reduced blue sensitivity)
@ NONE
No filter applied.
EntityType
Entity type enum - matches Cap'n Proto enum.
constexpr const char * SETTINGS_FILE_PATH
Default settings file path.
bool SaveSettings(const AccessibilitySettings &settings, const char *filePath=SETTINGS_FILE_PATH)
Save accessibility settings to file (C-style binary write)
bool LoadSettings(AccessibilitySettings &settings, const char *filePath=SETTINGS_FILE_PATH)
Load accessibility settings from file (C-style binary read)
int EstimateTextWidth(const std::string &text, int fontSize)
Estimate the width of text in pixels.
Definition TextUtils.hpp:27
Binary struct for storing accessibility settings.
ColorblindFilterType colorblindFilter
Colorblind filter type.
void SetDefaults()
Initialize with default values.