Skip to content

refactor(loadscreen): Refactor the single player load screen to use TheDisplay for intro video playback#2273

Open
Mauller wants to merge 2 commits intoTheSuperHackers:mainfrom
Mauller:Mauller/refactor-loadscreen-video-playback
Open

refactor(loadscreen): Refactor the single player load screen to use TheDisplay for intro video playback#2273
Mauller wants to merge 2 commits intoTheSuperHackers:mainfrom
Mauller:Mauller/refactor-loadscreen-video-playback

Conversation

@Mauller
Copy link

@Mauller Mauller commented Feb 8, 2026

Merge with rebase

This breaks out changes from #2053 that involve the refactoring of the video playback.

I split this into two commits, one with the changes to TheDisplay for adding extra functionality, the second is the load screen refactor changes.

The other changes will come along after for video scaling options and for disabling the custom overlay during video playback.

This also fixes how the video playback is displayed in the progress bar.
Now the video progress filles the entire bar before resetting the bar for the normal data loading portion of the intro screen.


  • Replicate in generals

@Mauller Mauller self-assigned this Feb 8, 2026
@Mauller Mauller added Minor Severity: Minor < Major < Critical < Blocker Gen Relates to Generals ZH Relates to Zero Hour Refactor Edits the code with insignificant behavior changes, is never user facing labels Feb 8, 2026
}

// if the display has a movie playing then we need to draw the displays video buffer
if (TheDisplay->isMoviePlaying())
Copy link
Author

@Mauller Mauller Feb 8, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is added in addition to the original drawing functionality as some screens still use the original method, such as the challenge load screen.

The challenge load screen does something more complex with it's video handling and needs looking at seperate from this change.

@greptile-apps
Copy link

greptile-apps bot commented Feb 8, 2026

Greptile Overview

Greptile Summary

Refactored single player load screen to use TheDisplay for video playback instead of managing video buffers locally. This centralizes video playback logic and simplifies the load screen implementation.

Key Changes:

  • Moved video buffer and stream management from SinglePlayerLoadScreen to Display base class
  • Added getMovieProgress() method to track video playback progress
  • Added parameter-less overloads for drawVideoBuffer() and drawScaledVideoBuffer() that use internal buffers
  • Simplified load screen video loop to call TheDisplay->playMovie() and poll isMoviePlaying()
  • Progress bar now updates based on actual video progress rather than frame count calculations
  • W3DGameWindow automatically renders video buffer when movie is playing

Issues Found:

  • One critical null pointer dereference issue in getMovieProgress() that needs fixing before merge

Confidence Score: 3/5

  • This PR has a critical null pointer dereference bug that must be fixed before merging
  • The refactoring is well-structured and simplifies the codebase by centralizing video playback logic. However, getMovieProgress() in Display.cpp:367 dereferences m_videoStream without null checks, which will cause a crash if called when no movie is playing. While the current usage in LoadScreen.cpp protects against this by checking isMoviePlaying() first, the method itself is unsafe and could be misused in future code.
  • GeneralsMD/Code/GameEngine/Source/GameClient/Display.cpp requires immediate attention to fix the null pointer dereference

Important Files Changed

Filename Overview
GeneralsMD/Code/GameEngine/Source/GameClient/Display.cpp Implemented getMovieProgress() to calculate video progress percentage; potential null pointer dereference if called outside of movie playback
GeneralsMD/Code/GameEngine/Source/GameClient/GUI/LoadScreen.cpp Refactored video playback to use TheDisplay's internal buffers; simplified loop logic; progress bar now updates based on movie progress; background window handling improved
GeneralsMD/Code/GameEngineDevice/Source/W3DDevice/GameClient/GUI/W3DGameWindow.cpp Added automatic rendering of TheDisplay's internal video buffer when a movie is playing

Sequence Diagram

sequenceDiagram
    participant LoadScreen as SinglePlayerLoadScreen
    participant Display as TheDisplay
    participant VideoPlayer as TheVideoPlayer
    participant WindowMgr as TheWindowManager
    participant GameWindow as W3DGameWindow

    LoadScreen->>LoadScreen: Hide background window
    LoadScreen->>LoadScreen: Enable progress bar
    LoadScreen->>Display: playMovie(movieLabel)
    Display->>VideoPlayer: open(movieLabel)
    VideoPlayer-->>Display: videoStream
    Display->>Display: createVideoBuffer()
    Display->>Display: Set m_videoStream & m_videoBuffer
    
    loop while isMoviePlaying()
        LoadScreen->>Display: getMovieProgress()
        Display-->>LoadScreen: progress percentage
        LoadScreen->>LoadScreen: Update progress bar
        LoadScreen->>WindowMgr: update()
        LoadScreen->>Display: update()
        LoadScreen->>Display: draw()
        Display->>GameWindow: drawVideoBuffer()
        GameWindow->>Display: drawVideoBuffer(coords)
        Display->>Display: Render video frame
    end
    
    LoadScreen->>Display: stopMovie()
    Display->>Display: Clean up m_videoStream & m_videoBuffer
    LoadScreen->>LoadScreen: Re-enable background window
Loading

Last reviewed commit: a71ec34

Copy link

@greptile-apps greptile-apps bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

3 files reviewed, 1 comment

Edit Code Review Agent Settings | Greptile

Comment on lines 502 to 522
@@ -548,51 +515,23 @@ void SinglePlayerLoadScreen::init( GameInfo *game )

TheGameEngine->serviceWindowsOS();

if(!m_videoStream->isFrameReady())
{
Sleep(1);
continue;
}

m_videoStream->frameDecompress();
m_videoStream->frameRender(m_videoBuffer);

// PULLED FROM THE MISSION DISK
// moveWindows( m_videoStream->frameIndex());

m_videoStream->frameNext();

if(m_videoBuffer)
m_loadScreen->winGetInstanceData()->setVideoBuffer(m_videoBuffer);
if(m_videoStream->frameIndex() % progressUpdateCount == 0)
{
shiftedPercent++;
if(shiftedPercent >0)
shiftedPercent = 0;
Int percent = (shiftedPercent + FRAME_FUDGE_ADD)/1.3;
UnicodeString per;
per.format(L"%d%%",percent);
TheMouse->setCursorTooltip(UnicodeString::TheEmptyString);
GadgetProgressBarSetProgress(m_progressBar, percent);
GadgetStaticTextSetText(m_percent, per);

}
TheWindowManager->update();

// redraw all views, update the GUI
TheWindowManager->update();
TheDisplay->update();
TheDisplay->draw();
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Progress bar update logic was removed during video playback. The old implementation updated the progress bar based on video frame count, but now the loop only checks isMoviePlaying() without updating any visual progress indicator. Check whether this removal was intentional.

Prompt To Fix With AI
This is a comment left during a code review.
Path: GeneralsMD/Code/GameEngine/Source/GameClient/GUI/LoadScreen.cpp
Line: 502:522

Comment:
Progress bar update logic was removed during video playback. The old implementation updated the progress bar based on video frame count, but now the loop only checks `isMoviePlaying()` without updating any visual progress indicator. Check whether this removal was intentional.

How can I resolve this? If you propose a fix, please make it concise.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The removal was intentional as the progress bar handling was already considered a hack and added nothing to the video playback

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It actually does show a loading bar at the bottom. Seen in USA 01 Mission Load Screen:

Image

Copy link
Author

@Mauller Mauller Feb 13, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It actually does show a loading bar at the bottom. Seen in USA 01 Mission Load Screen:

Image

i know, i removed the loading bar since it doesn't really add anything and the code behind it functioning for showing the video playback is hacky. The portion of the bar that progresses while the video plays back is a small 1/20 th of the bars overall length. So seems better to just use it to report loading progress.

The window it is part of also has to be hidden when rescaled videos are played otherwise it shows behind the video.

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the purpose of the loading bar is to show how long the video will play? Would be good to keep it.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the purpose of the loading bar is to show how long the video will play? Would be good to keep it.

I can check it again but i am sure the video doesn't fill the bar during playback, it only fills a tiny portion at the beginning and the rest is filled when the rest of the game data is loading.

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If that is the case, maybe we fix the loading bar. It should be possible to calculate the loading progress because the video length is known.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Managed to implement the video bar, while making it progress with the video playback, in an easier way than i initially expected.

Copy link

@xezon xezon left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does the loading bar in videos still work?

@Mauller
Copy link
Author

Mauller commented Feb 13, 2026

Does the loading bar in videos still work?

No i removed the video playback being part of the loading bar since the code behind it is hacky and it didn't add anything to the playback.
The window the bar is part of also needs hiding when rescaled videos are played otherwise the stretched background image shows behind the video.

@Mauller Mauller force-pushed the Mauller/refactor-loadscreen-video-playback branch from 54be1bc to a71ec34 Compare February 14, 2026 16:25
@Mauller
Copy link
Author

Mauller commented Feb 14, 2026

Tweaked to now show and properly update the progress bar during the video playback.

The bar now correctly displays where the video is during its playback, the bar then gets reset for the normal loading portion of the intro screen.

Copy link

@greptile-apps greptile-apps bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

8 files reviewed, 1 comment

Edit Code Review Agent Settings | Greptile

Comment on lines +367 to +370
Real Display::getMovieProgress()
{
return (Real)m_videoStream->frameIndex() / (Real)m_videoStream->frameCount() * 100.0f;
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Potential null pointer dereference if m_videoStream is null. Should check m_videoStream before dereferencing.

Suggested change
Real Display::getMovieProgress()
{
return (Real)m_videoStream->frameIndex() / (Real)m_videoStream->frameCount() * 100.0f;
}
Real Display::getMovieProgress()
{
if (m_videoStream == nullptr)
return 0.0f;
return (Real)m_videoStream->frameIndex() / (Real)m_videoStream->frameCount() * 100.0f;
}
Prompt To Fix With AI
This is a comment left during a code review.
Path: GeneralsMD/Code/GameEngine/Source/GameClient/Display.cpp
Line: 367:370

Comment:
Potential null pointer dereference if `m_videoStream` is null. Should check `m_videoStream` before dereferencing.

```suggestion
Real Display::getMovieProgress()
{
	if (m_videoStream == nullptr)
		return 0.0f;
	return (Real)m_videoStream->frameIndex() / (Real)m_videoStream->frameCount() * 100.0f;
}
```

How can I resolve this? If you propose a fix, please make it concise.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Gen Relates to Generals Minor Severity: Minor < Major < Critical < Blocker Refactor Edits the code with insignificant behavior changes, is never user facing ZH Relates to Zero Hour

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants