nmlgc / ssg

秋霜玉 / Shuusou Gyoku
MIT License
20 stars 5 forks source link

Alt-Tabbing out of the ending reloads wrong graphics #19

Closed nmlgc closed 11 months ago

nmlgc commented 1 year ago

Ending wrong graphics (small) Cellphone picture because it only appears in the original fullscreen mode where the regular Windows screenshot feature only gives you a black image, and the game's original screenshot feature (#15) isn't implemented yet. Will probably solve itself once we move away from DirectDraw (#4), but would otherwise be another bug we should probably fix.

nmlgc commented 11 months ago

This does in fact need to be fixed before implementing the OpenGL SDL backend.

This issue boils down to the game allocating all the DirectDraw offscreen surfaces it will ever use in a single place at startup:

https://github.com/nmlgc/ssg/blob/17894644715b372468f73b52eea1078e93b03344/GIAN07/LOADER.CPP#L87-L125

Most importantly, this defines their size. The specific bitmaps for each game state are then distributed across these fixed 9 surfaces (FACE_MAX is 3), and the loader simply blits their pixel data into these surfaces.

However, the endings use 6 separate 320×240 pictures, which are stored in 6 individual files inside GRAPH2.DAT. Loading each file into its own surface wouldn't work with the existing layout of surfaces and sizes. But instead of allocating 6 new surfaces just for the ending, the game does… uh, this:

https://github.com/nmlgc/ssg/blob/17894644715b372468f73b52eea1078e93b03344/GIAN07/LOADER.CPP#L175-L200

It loads each individual 320×240 picture into a temporary surface using the regular APIs, and then blits them into one of the four quadrants inside the bigger 640×480 surfaces that the regular game uses for enemy sprites and the Wide Shot bomb portrait. But it only uses a DirectDraw blitting call to directly write from the temporary surface onto the intended one.\ The big issue with DirectDraw (and probably 95% of the reason why it's so painful to use) is that its video memory surfaces get lost when changing the display mode, and need to be updated from retained copies in system memory. Therefore, writing just to a DirectDraw surface can only be a shallow way of replacing image data. The retained copies still contain the original enemy sprites and bomb portrait, which is exactly what the game then restores if these surfaces get lost when Alt-Tabbing or locking the screen.

Luckily, we already need dynamic surface generation to handle the dynamic sizes of generated text sprites. With this feature, we can simply designate 6 of the 9 surfaces for these 320×240 pictures during the ending, and the regular game will then recreate them in their originally intended size once it needs to load the in-game bitmaps again. Easier than bothering with replicating the original surface layout in GDI as well, matches the original video memory consumption, and removes yet another instance of DirectDraw-exclusive blitting calls in game code.