Widescreen support (aka multi-room rendering)

Open-source port of PoP that runs natively on Windows, Linux, etc.
FluffyQuack
Vizier
Vizier
Posts: 80
Joined: June 6th, 2004, 7:05 pm

Widescreen support (aka multi-room rendering)

Post by FluffyQuack »

First of all, thanks to NagyD and others for creating SDL-PoP! It's fun having access to C source code of a very faithful re-creation of DOS Prince of Persia.

Prince of Persia is possibly my favourite game ever, but one way I think it could be better (and I'm probably biased as my memory is really bad and despite re-playing the game countless times I don't remember the exact level layouts) is having an idea what's next as you move from screen to screen so you don't end up falling into bottomless pits, chompers, or spikes when running at full speed.

This is my progress so far. What the game shows by default:
prince 2021-12-04 23-44-16-734-crop-50.png
And my build:
prince 2021-12-04 23-44-16-734-50.png
There's still a bunch of bugs to fix and I'm considering to also implement smooth scrolling as you move between screens.
User avatar
Norbert
The Prince of Persia
The Prince of Persia
Posts: 5743
Joined: April 9th, 2009, 10:58 pm

Re: Widescreen support (aka multi-room rendering)

Post by Norbert »

I hope you don't mind this off-topic comment...
I noticed your post above is your 2nd here, 17.5 years after your 1st.
Now that is an impressive gap.
Welcome back. :lol:
FluffyQuack
Vizier
Vizier
Posts: 80
Joined: June 6th, 2004, 7:05 pm

Re: Widescreen support (aka multi-room rendering)

Post by FluffyQuack »

Norbert wrote: December 5th, 2021, 6:32 pm I hope you don't mind this off-topic comment...
I noticed your post above is your 2nd here, 17.5 years after your 1st.
Now that is an impressive gap.
Welcome back. :lol:
Yeah, it's a bit of a gap (insert gif of Matt Damon aging from Saving Private Ryan here). I could swear I was more active on these forums back then, but yeah, apparently it was just that one post.
FluffyQuack
Vizier
Vizier
Posts: 80
Joined: June 6th, 2004, 7:05 pm

Re: Widescreen support (aka multi-room rendering)

Post by FluffyQuack »

Here's a video of my current build:


There are some very minor issues (the pause menu can look slightly wonky and full-screen flashes don't cover the entire length of screen). I don't want to show any more details of rooms that are below or above since that would spoil what tiles are loose (which is why I went with widescreen as I don't think there's anything bad with showing a little bit of the rooms that are to the left and right), but it would probably be nice to have it smoothly scroll between rooms when moving vertically.

Either way, I think the current results are pretty good.
User avatar
Norbert
The Prince of Persia
The Prince of Persia
Posts: 5743
Joined: April 9th, 2009, 10:58 pm

Re: Widescreen support (aka multi-room rendering)

Post by Norbert »

Looks good, particularly with the smooth scrolling you've implemented.
The minor issues you mention sound solvable too.
In level 2, if you go 1 room left, then 1 room down, does it look okay?
Is the code on GitHub (your FluffyMod branch, maybe)?
FluffyQuack
Vizier
Vizier
Posts: 80
Joined: June 6th, 2004, 7:05 pm

Re: Widescreen support (aka multi-room rendering)

Post by FluffyQuack »

Uploaded another video (shows a comparison of the old and new rendering):
Norbert wrote: December 9th, 2021, 12:14 pm Looks good, particularly with the smooth scrolling you've implemented.
The minor issues you mention sound solvable too.
In level 2, if you go 1 room left, then 1 room down, does it look okay?
Is the code on GitHub (your FluffyMod branch, maybe)?
That room will look the same as in normal SDL-PoP (centred with black borders). It's easy enough to handle rooms that only lack a left or right room -- then I simply offset the camera -- but when a room lacks both a left and right room, then yeah, that's a bit harder to handle. Maybe a solution would be to dynamically draw a pattern of wall tiles that match up with the current room being rendered.

Cutscenes would be a bigger issue to fix. To prevent that from having borders I'd need all-new art.

And that's right, I'm working on the FluffyMod branch. I just released a Windows build of my fork now: https://github.com/FluffyQuack/SDLPoP/releases/tag/v0.1

This was my first time messing with the PoP code and I'm uncertain if I regret how I implemented this feature. I was inspired by the screenshot code that's capable of taking multiple screenshots of various rooms and then combining those into one big collage. My multi-room-rendering code is very similar to that code. If I had started from scratch now as I'm more familiar with the codebase, I think I would have just widened the resolution of the framebuffer and drawn additional columns to it rather than drawing multiple framebuffers and switching rooms for each one (though it's possible I would have encountered the same issues with a different method anyway).

I encountered some interesting problems which made me learn some behind-the-scenes stuff I never knew about the game. For instance, the final room in the final level is supposed to be the room with the princess, but in the actual level, it's just a generic empty room. I had to add in a hardcoded check for the camera to treat that room as non-existent so it's not shown in the widescreen rendering.

Here's a list of known issues:
  • Render position values aren't updated when window is manually resized.
  • Flash effects don't cover the entire width of the window (when wider than 4:3).
  • When the prince is rendered at the edge of a room (aka rendered in two rooms) his position might be off by one pixel in one room. I think this issue comes from the game's coordinate system (range is only 0-140).
  • Camera still moves while the game is paused.
  • Pause menu isn't always centred.
  • The skeleton enemy isn't visible in adjacent rooms if you leave him in the room he spawns (very minor issue as this can't happen during normal gameplay).
  • Shadow enemy isn't visible in adjacent rooms (minor issue as this is very unlikely to happen during normal gameplay).
  • Fuzzy and blurry scaling is broken right now.
  • 1:1.2 pixel ratio is currently enforced.
  • There's a column of black pixels if vertical window resolution is below 240.
  • I want to implement scrolling between rooms vertically.
Most of these issues wouldn't be that hard to fix (it's only the compatibility with older quicksaves and replays, and the prince rendering sometimes being off by one pixel at room edges, that would be very hard to solve). But I'm taking a break from now as I've spent a lot of time on this the past week and I think the feature works well overall.
User avatar
VelCheran
Vizier
Vizier
Posts: 127
Joined: May 28th, 2020, 7:26 pm

Re: Widescreen support (aka multi-room rendering)

Post by VelCheran »

I'd very much like to test the so called level 5 gate skip with this widescreen build. This trick can be seen there for instance. Basically, you have to face a guard and walk back with the good rhythm so that the left key is pressed every 0.1 second (this game runs on 12 FPS, except during fights where it slows down to 10 FPS, so one frame every 0.1 second). This prevents the game from changing room on screen. And for some reason it allows the kid to go through that closed gate on the left.

Some assumption among the community is that when he reaches the gate, the game loops to the right of the room instead of the left, and thus don't detect any obstacle. That would be because of an integer overflow, if I'm not mistaken.

So, to sum up: if we could see a wider room, we should in theory see the kid be teleported to the right when doing this trick.
FluffyQuack
Vizier
Vizier
Posts: 80
Joined: June 6th, 2004, 7:05 pm

Re: Widescreen support (aka multi-room rendering)

Post by FluffyQuack »

VelCheran wrote: December 10th, 2021, 12:28 am I'd very much like to test the so called level 5 gate skip with this widescreen build. This trick can be seen there for instance. Basically, you have to face a guard and walk back with the good rhythm so that the left key is pressed every 0.1 second (this game runs on 12 FPS, except during fights where it slows down to 10 FPS, so one frame every 0.1 second). This prevents the game from changing room on screen. And for some reason it allows the kid to go through that closed gate on the left.

Some assumption among the community is that when he reaches the gate, the game loops to the right of the room instead of the left, and thus don't detect any obstacle. That would be because of an integer overflow, if I'm not mistaken.

So, to sum up: if we could see a wider room, we should in theory see the kid be teleported to the right when doing this trick.
It's possible my fork has made that skip impossible to do. Each time the screen is fully redrawn it becomes impossible to change room for 2 ticks, which is something I removed when I changed how the screen drawing works. Maybe the exploit relies on triggering screen redraws somehow which prevents the game from changing room, though I'm not sure how that's possible by merely tapping left.

It would be possible to restore the original behaviour in my fork, though, by re-inserting

Code: Select all

exit_room_timer = 2;
to where the code would have normally done a full screen redraw.

I think the best way to figure out what's going on might during that exploit is to print the prince coordinates to the screen all the time, then you have an idea what's going on. The coordinate system in the game is very limited and very prone to weird stuff happening if it overflows or underflows when it's not supposed to.

When I've been working on the code, that's a part of me who is tempted to overhaul many systems. The coordinate system for the prince and guards has extremely low precision and is prone to overflows, there can only be one active guard in total, and there are arbitrary limitations all over the place (max 24 rooms per level, low max count of trobs, low max count of mobs, and etc).
dmitry_s
Developer
Developer
Posts: 148
Joined: July 27th, 2021, 7:22 am

Re: Widescreen support (aka multi-room rendering)

Post by dmitry_s »

I really like the idea and you are making a good progress.

Working with my Prince 1 1/2 mod I have a couple of ideas about some of your issues. https://www.popot.org/custom_levels.php?mod=0000232 - the source code is included.

1. Flash does not cover the entire screen - The "set_bg_attr" method is responsible for changing the background color. There is a "rect" variable that uses the "offscreen_surface" coordinates to set the cover size. It can probably be adjusted.

2. Guards/skeletons not visible - They only get visible the the "enter_guard" method is called when prince is entering a room. But you can add guard sprites to the object table based on the values stored in the "level" variable from adjacent an room. Each column has 5 invisible columns on each side (the most outer columns only has 1 or 2 pixels). So if a guard is on tile in column 8 in the room on the left, a guard sprite with the proper coordinates and color can be drawn in the column -2 of the room on the right. When prince enters the room on the last the sprite would become invisible and the real guard would appear. SDLPoP has an optional fix to the original game where dead guards appear in the next room if they died between rooms. It has the coordinate calculations needed.

My mod allows up to 3 guards (up to 5 dead) in each room using that technique. It has separate variables for guard sprites that get rendered in the object table in various frames (inactive, dead, etc). Only one guard is truly active at a time but inactive guards can also kill prince if he gets close to them through additional logic. Once an active guard dies it turns into a sprite (dead) and an active guard appears in place of an inactive sprite. Your use case is simpler.

There is a catch though. Currently only 1 guard color is supported per room. Not only the guard color variable is global but the guard palette is applied to all the guard sprites in the room. It can probably be changed but I went a simple way of having all guards on the level have the same uniform color with a couple of exceptions where it is impossible to get 2 guards together. If that happens, the inactive sprite would get changed to the color of the guard.
dmitry_s
Developer
Developer
Posts: 148
Joined: July 27th, 2021, 7:22 am

Re: Widescreen support (aka multi-room rendering)

Post by dmitry_s »

VelCheran wrote: December 10th, 2021, 12:28 am Some assumption among the community is that when he reaches the gate, the game loops to the right of the room instead of the left, and thus don't detect any obstacle. That would be because of an integer overflow, if I'm not mistaken.

So, to sum up: if we could see a wider room, we should in theory see the kid be teleported to the right when doing this trick.
Technically there is some teleportation involved when simply moving across rooms. But the issue here is how it happens.

On the bottom of page 7 of this doc you can see that there are 58 pixels on the side of a room that are invisible.
https://www.popot.org/documentation/doc ... mation.pdf

Each tile is 14 pixels wide means that are 5 columns (the ones on the edge are only 2 pixels wide) on each side of the room that are invisible, as I mentioned in the reply above. If the screen does not change in time prince will be moving across those tiles in the invisible area of the room. I believe the logic that checks gate collisions does not work correctly in columns further than 1 invisible column from the visible area of the room so prince is able to move until he hits a wall or falls into an invisible abyss.

When the room changes while prince is in an invisible column of the room, he is going to appear in the location of the next room that corresponds to the invisible column. For example, invisible column -2 (visible are 0-9) would correspond to column 8 of the next room, etc.

The room in the fight mode changes not only based on prince's coordinates but also his frame #. The original game has a bug that if you press "back" repeatedly, that frame will not get drawn until prince runs out of room to move.

Here is David's explanation from the source code:
By repeatedly pressing 'back' in a swordfight, you can retreat out of a room without the room changing. (Trick 35)

The game waits for a 'legal frame' (e.g. frame_170_stand_with_sword) until leaving is possible;
However, this frame is never reached if you press 'back' in the correct pattern!

Solution: also allow the room to be changed on frame_157_walk_with_sword
Note that this means that the delay for leaving rooms in a swordfight becomes noticably shorter.
User avatar
atrueprincefanfrom18
Site Shah
Site Shah
Posts: 1782
Joined: January 21st, 2020, 2:53 pm
Contact:

Re: Widescreen support (aka multi-room rendering)

Post by atrueprincefanfrom18 »

Amazing development!
Let's see how far it gets :)
Love to create new MODS :)

My complete list of mods until now!

My channel. Do consider subscribing it! :)
User avatar
VelCheran
Vizier
Vizier
Posts: 127
Joined: May 28th, 2020, 7:26 pm

Re: Widescreen support (aka multi-room rendering)

Post by VelCheran »

dmitry_s wrote: December 10th, 2021, 3:18 am
VelCheran wrote: December 10th, 2021, 12:28 am Some assumption among the community is that when he reaches the gate, the game loops to the right of the room instead of the left, and thus don't detect any obstacle. That would be because of an integer overflow, if I'm not mistaken.

So, to sum up: if we could see a wider room, we should in theory see the kid be teleported to the right when doing this trick.
Technically there is some teleportation involved when simply moving across rooms. But the issue here is how it happens.

On the bottom of page 7 of this doc you can see that there are 58 pixels on the side of a room that are invisible.
https://www.popot.org/documentation/doc ... mation.pdf

Each tile is 14 pixels wide means that are 5 columns (the ones on the edge are only 2 pixels wide) on each side of the room that are invisible, as I mentioned in the reply above. If the screen does not change in time prince will be moving across those tiles in the invisible area of the room. I believe the logic that checks gate collisions does not work correctly in columns further than 1 invisible column from the visible area of the room so prince is able to move until he hits a wall or falls into an invisible abyss.

When the room changes while prince is in an invisible column of the room, he is going to appear in the location of the next room that corresponds to the invisible column. For example, invisible column -2 (visible are 0-9) would correspond to column 8 of the next room, etc.

The room in the fight mode changes not only based on prince's coordinates but also his frame #. The original game has a bug that if you press "back" repeatedly, that frame will not get drawn until prince runs out of room to move.

Here is David's explanation from the source code:
By repeatedly pressing 'back' in a swordfight, you can retreat out of a room without the room changing. (Trick 35)

The game waits for a 'legal frame' (e.g. frame_170_stand_with_sword) until leaving is possible;
However, this frame is never reached if you press 'back' in the correct pattern!

Solution: also allow the room to be changed on frame_157_walk_with_sword
Note that this means that the delay for leaving rooms in a swordfight becomes noticably shorter.
Thanks for the explanation.
But there are definitely some teleportation involved, as seen in the TAS.
dmitry_s
Developer
Developer
Posts: 148
Joined: July 27th, 2021, 7:22 am

Re: Widescreen support (aka multi-room rendering)

Post by dmitry_s »

VelCheran wrote: December 10th, 2021, 12:14 pm Thanks for the explanation.
But there are definitely some teleportation involved, as seen in the TAS.
I have not seen this bug but I have seen a similar bug where the room and the tile column get out of sync. It can be reproduced in the original game if you push the second to last guard on level 11 into the next room onto spikes. He would appear behind a wall on the left of the room where prince is. The same thing can happen if you push a guard into chompers or a gate in the next room without switching to that room.

SDLPoP has a fix called "fix offscreen guards disappearing" which also fixed the bug described above. I would curious if the bug in the video can be reproduced with that option enabled. It looks like that might be a different but similar bug. But the suspect in the video is the open gate. I think what is happening is the drawn room is the room in the middle but prince is actually pushing the guard to the right from the room on the left. So the game puts the guard into the room on the right of the wrong room when the gate push logic is called. The room is probably not getting switched for the same reason as in level 5 so it could be a combination of 2 bugs.

And on top of that there is a bug with the wall push. It is incredible how TAS found this scenario.
dmitry_s
Developer
Developer
Posts: 148
Joined: July 27th, 2021, 7:22 am

Re: Widescreen support (aka multi-room rendering)

Post by dmitry_s »

Back to the original topic. It might be worth disabling the smooth scrolling in fight mode when you are fighting in between rooms.
David
The Prince of Persia
The Prince of Persia
Posts: 2846
Joined: December 11th, 2008, 9:48 pm
Location: Hungary

Re: Widescreen support (aka multi-room rendering)

Post by David »

When compiling with Dev-C++, I get these warnings:

1. [Warning] passing argument 2 of '_wstat' from incompatible pointer type
on this line:

Code: Select all

	int result = _wstat(filename_UTF16, _Stat); //Fluffy: Replaced call to wstat() with _wstat(). Is that safe?
In Dev-C++, the stat functions are defined as:

Code: Select all

(in <sys/stat.h>)
int __cdecl stat(const char *_Filename,struct stat *_Stat);
int __cdecl wstat(const wchar_t *_Filename,struct stat *_Stat);
  int __cdecl _wstat64i32(const wchar_t *_Name,struct _stat64i32 *_Stat);

(in <_mingw_stat64.h>)
#define _wstat _wstat64i32
I see you use MSVC.
MSVC has no wstat(), but defines _wstat() with the same type of second argument as regular stat().
(source).

You could use something like this:

Code: Select all

#ifdef _MSC_VER
	int result = _wstat(filename_UTF16, _Stat);
#else
	int result = wstat(filename_UTF16, _Stat);
#endif
2. [Warning] implicit declaration of function 'pow' [-Wimplicit-function-declaration]
To fix this, add #include <math.h> .

3. Not a warning, but a related thing in seg000.c:

Code: Select all

#include <math.h>

//Fluffy: Added this since we got compile error due to missing M_PI
#ifndef M_PI
#define M_PI  3.14159265358979323846264f  // from CRC
#endif
I looked it up, in MSVC you need to #define _USE_MATH_DEFINES to get M_PI from math.h.
(source)



In SDLPoP.ini these values let me play in full screen:

Code: Select all

pop_window_width = 1536
pop_window_height = 864
Windows multiplies them by 1.25, because scaling is set to 125%.
The result is a 1920×1080 window, which matches the desktop resolution I use.
Post Reply