mailto: blog -at- heyrick -dot- eu

What a difference a day can make!

Yesterday I made a start on translating my Mamie game to work under SDL/Linux. I had made an earlier test program, so it was time to transplant the code from that into the game to get that working.

What I have done is to try to keep as much of the RISC OS code as possible, and to section it off like:

#ifdef __riscos
   ...RISC OS specific stuff...
#else
   ...SDL/Linux stuff...
#endif

Sometimes I do it in reverse, like #ifdef __linux. For the very system specific things (like keyboard handling), the entire RISC OS code is wrapped in a conditional, and the 'else' clause brings in a file of the same name in a linux subdirectory.

Essentially, this is the source:

Mamie source code
Why does PHP's image resize now make blurry pictures? 🤷

And this is in the linux subdirectory:

Mamie Linux source code
Shadow versions for Linux.

Because of the differences between sprite handling between the two platforms, I have added a sprite handler that behaves in a manner similar to the RISC OS SpriteOp, or at least, as much of it as I actually use. It loads all of the images, as PNG (with transparency if applicable) from the assets directory, translates them into something the blitter can put on the screen, and when necessary, do the plotting. There are a little over two hundred sprites, all saved out one by one from Paint (which, luckily, can now export PNG and transparency works too).

And, finally, a linriscos file that contains a random selection of, mostly DeskLib, functions in a Linux form. Such read Time_Monotonic() which on RISC OS will return the value of the centisecond ticker, while on Linux will return the SDL 'ticks' value divided by ten (as it's a millisecond count).

Both sprite and linriscos are held within the main directory with the RISC OS code so I don't need to touch anything to get the build to work.
If I edit the linux/key.c file, make cannot see that, so I have to touch the RISC OS key.c file and then make is like "oh, this needs to be rebuilt" and so it does (and it pulls in the Linux code in its place).
I did think of putting the code all together with an "l" prefix for Linux, but that just seemed messy. There might be a better way, but what I'm doing works so...
And, of course, there's always make clean followed by make to perform a full rebuild.

 

Yesterday I jumped through a few hoops in order to bodge a windowed mode with a slightly reduced height (680 pixels) because my screen is 1366×768 and with the icon bar at the bottom and the window title at the top, there wasn't room for the full 720 pixels. This is done to aid testing as requesting a fullscreen mode causes a fair number of screen redraws as SDL opens the window, switches to an actual 1280×720 mode, opens the window again, then opens it fullscreen. And sometimes the video driver chokes going back to native resolution leaving me with a blank display until I shut the lid (put the machine to sleep) and wake it up again. My sound is flaky too, I blame Intel's chipset and some proprietary nonsense that maybe isn't 100% supported by Linux...

Well, today I discovered the SDL_WINDOW_FULLSCREEN_DESKTOP flag. What this does is to simply open the window fullscreen, but not change the resolution. When I later specify that the window dimensions are 1280×720, it'll just scale that to fit the screen. It looks a bit naff at times due to the scaling, but it's a lot faster (useful for testing) and - since it doesn't bash the video hardware - isn't prone to breakage. I might add a command line switch to make this an option.

The next job was to fix the positions of things. The menu in the video yesterday was a fake. In order to bring in the actual RISC OS menu code, I had to modify the font and sprite plotters to nudge the Y offset of everything. You see, in RISC OS the co-ordinate 0,0 specifies the bottom left of the screen, while in SDL it's the top left. So to get the desired position, it's the screen height minus the wanted Y offset minus the height of the object itself.

I have added support for font colours. This simply defines an array where each of the four font handles points to one of the array elements, which can be set and then read.

Flicker has been removed by getting rid of all of the calls to sync the render buffer with the window, and simply doing it once in the function that switches screen banks. Those are dummy functions now, as SDL takes care of banking (or, rather, everything is rendered to an off-screen buffer and blitted to the screen (window) when an update is requested). Superficially this is similar to buffer switching, so the function to select which buffer is visible simply updates the screen. The one to select which buffer to write to...does nothing.

The level loading and parsing now works. After a bit of head scratching and weirdness, I realised that I needed to pass a flag to GCC to force chars to be unsigned. This wasn't ever specified in the original code because that's just how Norcroft did it. It's up to the compiler what it does, but there doesn't seem - to me - to be much logic in having a char array default to be signed, given that any high-bit-set characters will end up with unexpected negative values. There may be some historical reason for this, but whatever.
Now, I am well aware that the correct answer is to change the code. But the code I have works and builds on RISC OS so I want to change it as little as possible to support a Linux incarnation. At least, that's the theory. ☺

I need to add lots of Linux conditionals to insert SDL polling into the wait loops. I've had to do this with the menu as even though one can mostly ignore the SDL events and just bang stuff to the screen and such, after a few moments Linux will pop up a "This program isn't responding. Wait or Force close?" prompt.

 

The big job, and one I was procrastinating over because I wasn't looking forward to it, was to sort out the keyboard handling. I decided that, for now, I'm only going to support the default keypresses.
Well, with that, everything became a whole lot easier. In the SDL poll loop, I look for key down and key up events, and then I change the state of the keys I'm interested in as applicable. When a key is requested (by internal RISC OS key code), I look to see if that's a known key. If it is, the state is returned. If it isn't, the key is "not pressed" because it simply doesn't exist as far as the key handling cares.

 

Once that was done, and some polling was added to repeating loops (like awaiting a keypress), it turns out that - actually - that was all that was required in order to get the core of the game to build and run.

Don't get me wrong - there's a lot missing - no sound effects, no rectangle plotting (hence no camera flash), and various other things missing. But, look, it's a massive leap forward to be able to play Mamie...on Linux!

 

Some tricks I picked up along the way today. This is mostly for me to be a reminder, but I'll put it here in case it's useful to anybody else.

  • To merge audio (recorded on my phone) with a screen recording:
    ffmpeg -i <input_video> -itsoffset 1.5 -i <input_audio> -map 0:v -map 1:a -c:v copy -c:a copy <output_file.mp4>
    The -itsoffset, measured in seconds (and can be negative) adjusts the relative offsets of the audio to the video given that it's rather unlikely that starting two different recordings will result in perfect synchronisation.
  • To work out where something crashed, build it with the -g compiler option. Then load it with gdb <progname>. Enter the command r to start it running.
    After it crashes, enter bt to see the call stack, that'll often show where it blew up a few entries above the program termination functions. You can breakpoint at functions with b <function>.
    When you hit the breakpoint, use s (for step) to single-step - but don't use this, it's best to step over functions (rather than into them) using n (for next) unless you specifically want to go into a function. Why? Because otherwise you'll get lost in the library code...
    Use c (for continue) to resume normal execution, or f (for finish) to run until the end of the current function.
    print <variable> will show you a variable. You can use set <variable>=<value> to change it.
    There is also layout next (or prev) to change how gdb looks, but this tends to break and just look bad.
  • To associate an icon with the program, this can be added to the makefile following the command to build the executable:
    gio set -t string $(EXECUTABLE) metadata::custom-icon file:///<full_path_to_png_file>
    You can use gio info <file> for more info than you wanted to know...

 

More bad English

I have to transfer scary corrosive chemicals from a big tank (900-950 litres) into smaller (5 or 20 litre) containers for use in the production area.
And this is a label that is stuck to the container. I guess people were having trouble with the new valve system.

A confused sticker
A confused sticker.

First up: Dear Diversey, these new valves suck arse. There is no finesse, the thing has a harsh click action so it's either closed or open, there's not much in-between.

Secondly, and this is a potential legal issue, why the hell is the sticker in English on a product destined for France?

Thirdly, let's look at what it says. Essentially there are three steps to getting the valve to open, as shown by the pictures:

  1. Lift that little yellow tab
  2. Check it is lifted
  3. Crank the handle
Okay, it's really two steps but the one in the middle is for dumb people. Whatever.

Now let's look at the text. Because this is where it all gets a bit confused.
The three part programme is clear enough, for the most part, except it's a bit dumb to say "yellow*" with the star being a note to say that your little clip tab thing might not actually be yellow. Duh.

Now let's look at the diagram text. This is where the wheels fall off.

Step one. The thing is closed. The text says "CLOSED". Good.

Step two. The thing is closed. The text says "OPEN". What?

Here's the thing - they are using Open and Closed to refer to the valve, and they are using the same Open and Closed words to refer to the tab.

The problem is, this is wrong for two reasons.

The first bit of wrongness is that this is confused. When talking about opening a valve, it's not good form to use the same word to refer to whatever safety interlock there may be.

And secondly, moving the tab (or clip) doesn't actually "open" anything. There is no "openness" here. It's just a piece of plastic sliding up to let the handle turn.

A much better word pair would be LOCKED (tab down) and UNLOCKED (tab up). This not only better describes what is actually happening, it avoids using the same words that would be used to describe the actual valve.

 

Time changes everything

Over the Loire, just after Liré, was a big wooden press. It was set by the side of the road, and was just one of those quaint little oddities. It's been there ever since I came to France and mom and I would "go south".

The last time we went down there would have been the Spring of 2019. I know we didn't in the summer because I spent that summer by myself while mom was in hospital. The latest photo I can find is the 12th of February 2019. I don't know if there was any later.

The big press is at 47°18'42.8"N, 1°09'42.3"W (or 47.311900, -1,161760).

A screenshot from Google Street View
An old press, been there for ages.

Google lies when it says © 2025, this imagery is 14 years old.

If we hop just a tiny bit to the left (west) to put ourselves on the main road, well... we get a more recent image and... oh.

A screenshot from Google Street View
:(

It's yet another roundabout. And the press? Doesn't appear to have been moved, it looks like it has been discarded.

 

In a town called Mouzillon, there was a roundabout with a big piece of pottery that said "MUSCADET" in big letters. That was actually the very last photo that I took "down south", and one of the photos I printed for mom to have on the wall in her room.

A big amphora on a roundabout.
Photo taken two months before it was destroyed.

Unfortunately a car accident in April 2019 wrecked the big amphora, the tree, and sadly killed the passenger. Such violence, I can't believe they were doing anything like the speed limit to cause that much damage, but... Article here (in French, obviously).

Looking at the reviews of the cute little restaurant attached to the supermarket in Clisson, one stands out: I'm very disappointed with what the Olive Grove has become. No more starters, no more cooking by the chef, no more homemade fries, what a shame..

If I ever get a driving licence and take myself back to Clisson, I can expect I might do it once to say I did it, and then no more because it just won't be the same. It seems like enshittification is happening everywhere these days. ☹

It's the main reason I rarely go to Big Town these days, nor do I bother much with vide greniers. Châteaubriant and the like were so much better as shared experiences. By myself? What's the point if there isn't something specific that I'm going for...

 

 

Your comments:

Please note that while I check this page every so often, I am not able to control what users write; therefore I disclaim all liability for unpleasant and/or infringing and/or defamatory material. Undesired content will be removed as soon as it is noticed. By leaving a comment, you agree not to post material that is illegal or in bad taste, and you should be aware that the time and your IP address are both recorded, should it be necessary to find out who you are. Oh, and don't bother trying to inline HTML. I'm not that stupid! ☺
As of February 2025, commenting is no longer available to UK residents, following the implementation of the vague and overly broad Online Safety Act. You must tick the box below to verify that you are not a UK resident, and you expressly agree if you are in fact a UK resident that you will indemnify me (Richard Murray), as well as the person maintaining my site (Rob O'Donnell), the hosting providers, and so on. It's a shitty law, complain to your MP.
It's not that I don't want to hear from my British friends, it's because your country makes stupid laws.

 
You can now follow comment additions with the comment RSS feed. This is distinct from the b.log RSS feed, so you can subscribe to one or both as you wish.

jgh, 10th November 2025, 13:26
As you go through the code, you'll find it easier to structure the source along the lines of: 
src 
+-riscos 
| +--key.c 
| +--sprite.c 
| etc 
+-linux 
| +--key.c 
| +--sprite.c 
| etc 
+-main.c 
+-etc. 
 
and in your code, eg: 
#ifdef __riscos 
#include riscos/blah 
#elifdef __linux 
#include linux/blah 
etc. 
 
That's how stuff like BrandyBasic, InfoZip, cZ80Tube, BeebEm, BBC BASIC for SDL, etc. are structured. 
Zerosquare, 10th November 2025, 14:13
The "after" picture for the press is the same as the "before" one.
Rick, 10th November 2025, 17:08
Zerosquare: Thanks, fixed. 👍 
 
jgh: I didn't want to mess around too much with the layout of the existing source. 
jgh, 10th November 2025, 18:40
Actually checking my code to remind myself :p my code structure is usually: 
src 
+--local.h 
+--main.c 
+--etc 

+--riscos.c 
+--unix.c 
+--win. c 
enh, 11th November 2025, 17:22
> There may be some historical reason for this, but whatever. 
 
the whole "unlike everyone else, arm uses unsigned char" thing is because the arm2 ldrb instruction does a zero-extend (as if it's an unsigned byte), and had no ldrsb to load a byte and sign-extend, nor any sxtb to sign-extend. code generation for the really common operation of loading a byte from memory would have been pretty bad if the c compiler had defaulted to char being signed. 
 
as you say, unlike short/int/long, c leaves the signedness of plain `char` undefined to allow for this kind of thing, but for any architecture where signed char and unsigned char are equally cheap, it's more consistent to have all the integer types default to signed. (and, of course, more portable because "that's what [almost] everyone else is doing".) 
 
but going back to history, aiui the pdp-11 only did sign extension on loads, so the performance argument was the opposite of the arm2 one for the original implementation. 
 
you're not wrong though --- as with java's signed `byte` type, while it's consistent with larger types, it isn't necessary a useful choice, given that you're a lot more likely to be doing bit manipulation with a byte. at least c -- unlike java -- lets you say `unsigned char` or `uint8_t` when that's what you want!
jgh, 13th November 2025, 07:18
Yes, that caught me out early on with the PDP11. MOVB src,Rn is the only byte instruction that sets b8-b15 of the destination. You cannot load b0-b7 of a register without also loading b8-b15. But loads are the only instruction that does that. You can do things like INCB Rn and only increment b0-b7! That actually comes in quite useful in places. CLRB Rn - just clear b0-b7. TSTB Rn - just test if b0-b7=0. RORB Rn - rotate b0-b7! :D

Add a comment (v0.12) [help?] . . . try the comment feed!
Your name
Your email (optional)
Validation Are you real? Please type 94064 backwards.
UK resident
Your comment
French flagSpanish flagJapanese flag
Calendar
«   November 2025   »
MonTueWedThuFriSatSun
     
34567
111213141516
17182021
242526272829

(Felicity? Marte? Find out!)

Last 5 entries

List all b.log entries

Return to the site index

Geekery
 
Alphabetical:

Search

Search Rick's b.log!

PS: Don't try to be clever.
It's a simple substring match.

Etc...

Last read at 15:00 on 2025/12/14.

QR code


Valid HTML 4.01 Transitional
Valid CSS
Valid RSS 2.0

 

© 2025 Rick Murray
This web page is licenced for your personal, private, non-commercial use only. No automated processing by advertising systems is permitted.
RIPA notice: No consent is given for interception of page transmission.

 

Have you noticed the watermarks on pictures?
Next entry - 2025/11/10
Return to top of page