Rendering a Room Viewport on top of a GUI

Started by vga256, 19 Oct 2021, 17:44

« previous - next »

vga256

I've been building a windowing system for a game I'm working on, and I've got most of the window behaviour worked out. Windows can stack, push to the front, etc.

One very specific requirement I have is that Rooms must be shown inside of windows. For that, I've been using the new Camera/Viewport system that CW designed.
Now, I understand that putting a Room "inside of" a GUI window frame is not the intended use of rooms, but I've worked around that by creating a GUI composed of a window frame with a transparent box inside. Currently, the Room viewport sits inside of the GUI frame, and works perfectly.

The problem I'm having is that, from what I can see, AGS internally renders all GUIs on top of Rooms, regardless of the z-order. There does not appear to be a "global z-order" that sets the stacking order of all rendered GUIs, Overlays, Rooms, Objects, etc. The outcome of this is that when I drag the Room window on top of a GUI, the GUI stays on top. As you can see in the attached image, the file transfer GUI is on top of the Room viewport (correct), but the modem dialer is also on top of the room window (incorrect).

tldr: Can someone think up a workaround that would allow me to push a Room viewport on top of a GUI?


Crimson Wizard

#1
I've been wondering for a while if that would be feasible to make viewports sort in the same stack as GUI. In the wip 3.6.0 we already made Overlays sorted among GUIs. With Viewports it's somewhat more complicated because they are sub-lists of things, so they would have to be fit in the middle of several lists of GUIs (unfortunately the way it's written currently, it's flat lists of drawn things rather than a proper "node tree"). But I think it's rather the issue of "ugly" code organization than the technical capability.

As for the workaround, if you are absolutely positive about having your viewport dragged above other GUI, then this goes down to simulating GUIs being covered by it. There might be several methods to achieve this. The dumbest I may think of is to resize GUI, reducing it's width and height (that will clip everything on it). However the problem with this is that the viewport may be dragged "diagonally" over one.

So, the trick may be to have each GUI composed of 2 identical GUIs with all controls repeated on them, sticked together. When viewport is dragged over this GUI, you resize one or both sub-GUIs to create a shape with a cut out side or corner.

EDIT: right, I realized that besides resizing GUI you will also have to offset its controls (depends on which direction you are resizing).

EDIT2: if you suppose the viewport may be actually small enough (resizing?), then it will be 3 GUI.

Here's a mockup of what I mean: black rectangle is the implied GUI border, colored rectangles are 2 or 3 GUIs that compose a larger pseudo-GUI, while white cuts are areas "covered" by the viewport:




vga256

Thanks CW. I hadn't thought of clipping down other GUIs - I think that's a good candidate for a workaround.

Given how specific my needs are for this project, I'd be hesitant to push for any kinds of changes to the engine/renderer code myself. Having a universal z-order, however, would bring AGS more in-line with other engines like Unity.

That being said, I'm enjoying finding workarounds for all this. The new Viewport system has to be one of the best, and under-utilized, parts of AGS.

Crimson Wizard

#3
Quote from: vga256 on 19 Oct 2021, 18:26
Given how specific my needs are for this project, I'd be hesitant to push for any kinds of changes to the engine/renderer code myself. Having a universal z-order, however, would bring AGS more in-line with other engines like Unity.

I have strong doubts about fully universal z-order, because that might overcomplicate it and allow users to do weird unexpected things. Currently I tend to think of AGS to have two separate coordinate spaces: UI and Room. Having everything in the same coordinate space would require a change of engine's paradigm (let alone complete rewrite of drawing logic, especially for the "software renderer").

But having just viewports sorted among UI is a more achievable thing and still logical in the AGS context imo. This basically makes room viewport an "overlay" with room camera drawn inside. I might have derived Viewport from Overlay now that I think about it; but with AGS development it's always been shoveling things in using the seemingly simpliest way...

vga256

Ah, right - completely forgot about the division of coordinate spaces.

Cassiebsg

This is just a suggestion that comes to mind, no idea if it would work or not, since I don't know if you have animation going one in the viewport when you drag it.

But considering that maybe it's just a still image, maybe you could take a screenshot of the viewport room, and then use that as the BG for your GUI while you are dragging it around. Then once you stop dragging you would just turn back to the normal transparent BG to see the room. (or if it's easier, just have a dummy GUI with the BG screenshot and switch to it while dragging).
There are those who believe that life here began out there...

vga256

#6
Quote from: Cassiebsg on 20 Oct 2021, 10:23
But considering that maybe it's just a still image, maybe you could take a screenshot of the viewport room, and then use that as the BG for your GUI while you are dragging it around. Then once you stop dragging you would just turn back to the normal transparent BG to see the room. (or if it's easier, just have a dummy GUI with the BG screenshot and switch to it while dragging).

Haha yup, this was my original plan! I'm fairly sure I can just pause animations in the room when the GUI is forced to the background.

vga256

#7
I am happy to report that I now have a working implementation. I created a completely invisible dummy GUI called "Occluder" that receives the same X/Y position as the Room GUI. When the Room GUI is set to Active (currently on top of other windows), the Occluder GUI is populated with a new backgroundgraphic:
Code: ags

  newOccluderSprite = DynamicSprite.CreateFromDrawingSurface(roomBackgroundSurface, 0, 0, roomBackgroundSurface.Width, roomBackgroundSurface.Height);
  gOccluder.BackgroundGraphic = newOccluderSprite.Graphic;

In other words, I'm simplying copying the Room's background surface onto a new sprite, then setting that sprite as the background of the Occluder GUI. After that, I set the Occluder GUI to be on top of the Room. When the Room GUI is inactive (behind another GUI), the Occluder gui is hidden.

Although this is twice as much rendering as we'd normally have, there do not seem to be any obvious performance penalties, and the implementation yields perfect behavior.

Video demonstration here.

Update: I realized that having an extra dummy/Occluder GUI is not even necessary - I can just use modify the background image of the Room GUI itself.

Khris

I'd have suggested that from the start but thought you might have objects and the like in your rooms. If it's just a static image, that's gonna make things easier :)
You don't actually need a room background in that case, just put the background sprite on a GUI instead.

Crimson Wizard

Quote from: Khris on 21 Oct 2021, 08:11
I'd have suggested that from the start but thought you might have objects and the like in your rooms. If it's just a static image, that's gonna make things easier :)
You don't actually need a room background in that case, just put the background sprite on a GUI instead.

Yes same, if there are no moving things, no characters walking etc, it may be easier to just make a GUI with room image on background and and transparent buttons for hotspots. The only problem I anticipate is that AGS does not support pixel-perfect detection for buttons for some reason, so if you want to have that you'd need to either script click detection by reading their graphic into dynamic sprites, or by shaping hotspots out of several buttons.

vga256

#10
Ah, okay - so I did not anticipate any of this because I have not implemented any room logic yet! Yes, the plan was always to have character animations, Objects and Hotspots - so I guess my ultra simple implementation will not work. Back to the drawing board.

Will post an update when I start trying to actually build a usable room.

eri0o

Hey, there's both a module and an plugin for fakescreen, which can render a room space in a sprite, you can then apply this sprite anywhere. It's slow, and won't work in very high resolutions or in a room with a lot of things, but it may be a possible workaround to keep in mind too.

vga256

Neat! I'll look into that module. Thanks.

SMF spam blocked by CleanTalk