With the caveat that I’ve barely touched the color code in Gargoyle, I think what’s happening is this:
When you call garglk_set_zcolors, Gargoyle sets global color override variables (gli_override_fg and gli_override_bg). And unless an individual character has its own color set, when the screen is drawn, those color overrides are used.
So the color works in Gargoyle because of this sledgehammer approach: when the upper window is drawn, it inherits the global colors, regardless of when they were set. It also means that colors don’t work quite in accordance with the standard says. Gargoyle is too optimistic, let’s say, in setting screen colors.
Way back in the days when Gargoyle was hosted on Google Code I reported a bug around this very issue:
I haven’t put much effort into this bug since things have been “good enough” with games that use colors. I guess SameGame, as I noted in the bug report, is one that does have issues…
I think part of the problem, too, is Glk’s window model vs the Z-machine’s… @erase_window -1 should set the whole screen to the current background color (which is global, not per-window). Then when the upper window is opened, it’s already the background color since Z-machine windows are just “viewports” into the current screen. But Glk’s window is an actual window. So when it’s split, it should have the same background color as the current color. And if I had to hazard a guess I’d say that requirement is why Tor Andersson implemented colors the way that he did. Because it works well enough, I suppose, for the majority of use cases. It fakes it: the current background color is just used everywhere unless text has already been written in a specific color.
There is probably a better approach to all this, but I’d have to give it some more thought.
Wow, that’s wild. I might have occasionally seen it, but I’d forgotten about it. Being able to retroactively change the styling of already emitted text would be a very cool feature, but it really should be explicit, not accidental. And especially because garglk_set_zcolors is implemented as gli_set_zcolors(gli_currentstr, fg, bg);, so changing global state is not what you’d expect from seeing that.
Could Bocfel just change the colours of all windows when @set_colour is called? Perhaps in set_current_style would be best? (There are a lot of calls to set_window_style(mainwin) so I’m not sure which function would be the best to set all styles in.)
I checked what I did in ZVM, and its @set_colour sets colours for all open windows, though @set_style doesn’t set style/reverse for all windows, just the current stream. Ah, but then @set_window sets style/reverse for the new window, so that’s the same result.
If you excised the gli_override_fg code then these extension APIs would be strictly window/stream specific and there’d be much less magic in our Glk implementations, and then Bocfel could just use them as needed to implement the Z-Machine spec. That just feels like the right solution to me.
That probably won’t cause any problems. Gargoyle should continue to function normally, and if it fixes things for you, then it’s worth it. In set_window_style, where garglk_set_zcolors is called, can you try replacing that call with:
Do you have a writeup anywhere of how to build and run all this? If I got this running locally I could do some more hands-on testing.
I will do some work on that and see how it goes. It’s not as easy as just removing the global overrides, as those are kind of tightly coupled to some other parts of the code. But I’ll see what I can manage.
Thanks, I’ll give that a try. As well as explain how to build Parchment from source…
No pressure at all. I think it would be good to change what garglk is doing, but more so from the perspective of having a very clear description of what garglk_set_zcolors actually does. Having it affect already printed text in other windows would be both very hard to specify, as well as probably unimplementable in some interpreters.
I’m not completely sure what the right thing to do is. Consider this Inform program:
[Split1;
! Whole screen is blue. Top 5 lines are empty (upper window).
! "Hello", yellow on blue, in the main window.
@set_colour 5 6;
@erase_window -1;
@split_window 5;
print "Hello";
];
[Split2;
! Whole screen is red, except the top 5 lines (upper window) are green.
! Then "Hello", in the main window, is yellow on green.
@set_colour 5 3;
@erase_window -1;
@split_window 5;
@set_colour 5 4;
@erase_window 1;
print "Hello...";
];
[Main;
Split1();
@read_char 1 -> sp;
];
(call either Split1 or Split2, but not both)
I’ve noted what these are supposed to look like, based on my reading of the standard and the output of Infocom’s DOS interpreter as well as Windows Frotz which seems to get everything right, all the time.
How to set up Parchment testing branch for local development. Note that the dev scripts are only really designed for running in Linux, and need Node and Docker to be installed.
git clone -b testing --recurse-submodules https://github.com/curiousdannii/parchment.git
cd parchment
npm install
npm run link-local-emglken
./src/upstream/emglken/build.sh
npm start
I’ve just tested your suggested change to Bocfel’s set_window_style, and it fixes both Photopia, as well as your split1/2 test.
I haven’t committed the patch myself yet, as I’m currently including garglk/garglk directly as a submodule, and switching to my fork of garglk could cause issues with anyone else with a copy of Parchment (Git doesn’t always play nicely with changing submodule sources.) But don’t feel like you need to update garglk quickly, I can always switch to my garglk repo later if needed.
Thanks! Building and running works like a charm here.
With the Bocfel patch I see both working properly here, as well. I definitely will spend some time trying to get Gargoyle to do purely per-window colors.
One note: the following program does not behave properly with Parchment (or, of course, Gargoyle). It splits the window, coloring the top green and the bottom red. When you hit a key, the upper window is expanded to 10 from 5. According to the Z-machine standard, when that @split_window 10 call happens, the screen should not change: the upper window will be half green and half red (from the earlier @erase_window call).
You can see the expected behavior in Frotz/Windows Frotz. This might be one that’s not particularly feasible in Glk, but it’s probably also something that games don’t actually do.
[Main;
@set_colour 1 3; ! Red
@erase_window -1;
@split_window 5;
@set_colour 1 4; ! Green
@erase_window 1;
@set_window 1;
@set_cursor 5 1;
print "[Press a key]";
@read_char 1 -> sp;
print " Splitting. Colors should not have changed.";
@set_window 0;
@split_window 10;
@read_char 1 -> sp;
];
Basic sound support is live on the testing site now! Parchment
I haven’t added support for the pause/unpause functions yet, and there’s no support for MOD files.
Turns out that web audio is still a mess. No browser supports all the formats we’d want to support - Chrome doesn’t support AIFF, and Safari doesn’t support Ogg. I ended up making a mini Rust library to decode AIFF and Ogg, using the Symphonia library. I haven’t found a good solution for MOD files yet, but based on previous forum discussions it seems like they haven’t actually been used very much? I’m thinking I’ll just not even try to add MOD support.
If a game tries to play sound as it starts then it won’t work; that’s an important browser anti-nuisance feature. I’m thinking for iplayif.com that I can make it detect whether an initial sound is played and switch to using a play button, so that it will only try to play sounds after a user event. But that won’t help with Parchment used elsewhere than iplayif.com. Should other uses of Parchment default to having a play button? But the previous discussion on play buttons was pretty negative… (Should Parchment autoplay or have a play button?)
@zarf I have a question about gestalts. In order for the advanced functions to be used I have to say that I support gestalt_Sound2. That gestalt implies gestalt_SoundMusic is supported. I’m already making glk_schannel_play return 0 if the sound is a MOD, but do you think it would be appropriate to also make gestalt_SoundMusic be unsupported, even though gestalt_Sound2 is supported? But the spec does say “This selector is guaranteed to return 1 if gestalt_Sound2 does.”, which is pretty definite…
Is all the functionality of the sound test, except MODs, expected to work? For example, typing LOOP at the initial prompt is supposed to loop the AIFF wind sound indefinitely, but currently there is only silence.
I guess follow that line. All the functions are available. Calling them won’t cause a fatal “selector not recognized” error. That’s what Sound2 conveys.
I should have thought about finer-grained queries when I came up with this, but oh well. :)
I’ve finished the rest of the sound API, and from running the sound test, I think it’s all working. (Except still no MOD support.)
For handling startup sounds, I’m thinking of adding a flag which will tell Parchment to use a play button. iplayif.com will set the flag if it can detect that start sounds are used, but if, for example, someone’s using the site generator, then they could add the flag themselves. Probably the best option, unless everyone has changed to be pro play button in general?
Autoplay option and play button have been implemented!
Here is Kerkerkruip with both options. The option can be specified in the URL, which is actually convenient in this case, because my plan for checking the RemGlk output wouldn’t work in this case - the first output of Kerkerkruip asks if you want to enable screen reader mode, so it’s only on subsequent plays that it would play sounds on startup. Maybe I can add a hardcoded list to autoplaying songs to iplayif.com so it can turn off autoplaying for games like this which only sometimes play sounds on startup?
Pretty much everything on my list has been crossed off, so I think I’m ready to merge the testing branch into master! If anyone wanted to do any final testing of Parchment, now is the time.
I’ve also published Emglken v0.7.0, which is just wrapping up the RemGlk-rs update.
For what it is worth, both options seem to behave the same in Safari on macOS. Music will only start playing automatically if testing.iplayif.com is whitelisted in the settings to “allow all auto-play”. Otherwise it won’t play any music until sound is switched off and then on again on the intro screen. [EDIT: In other words, it weirdly does not seem to count the initial click on the Play! button as a user interaction.]
Firefox and Brave will both play the music with the second link, but not with the first, which I think is the intended behaviour.