Got some Scala bindings for WiringPi thanks to SN-Bindgen (plus some manual adjustments)

https://gist.github.com/JD557/c81ad69f7506c70a5c26e9ddec24db27

Took me quite some time to get things to work... but at least I got a blinking LED today 😅 :

import wiringpi.all.*

println("Starting")
wiringPiSetup()

val led = 25

pinMode(led, OUTPUT)

while(true) {
  println("ON")
  digitalWrite(led, HIGH)
  Thread.sleep(1000)
  println("OFF")
  digitalWrite(led, LOW)
  Thread.sleep(1000)
}

I do need to figure out how to cross compile before I try something more complex... Scala Native compilation on a Raspberry Pi 3 B is SLOW! 😬

GIF

I've been flashing some Raspberry Pis recently and damn, this new Raspberry Pi Imager 2 (https://www.raspberrypi.com/news/a-new-raspberry-pi-imager/) is awesome.

Not only does the wizard includes a bunch of images (so no more searching for ISOs of common distros) it let's me configure credentials, SSH and Wi-Fi from the get go. That's a huge time saver for the initial setup. 🔥

João Costa shared 3 days ago
João Costa shared 4 days ago

I know that this is kind of creepy in the "being spied sense", but I kind of love how, after searching/buying any maker adjacent thing (e.g. 3d printer filament, smart home devices...), ad networks start treating me like the coolest guy ever. 😎

I buy a couple of small things and immediately start getting ads like:

  • "Buy this CNC mill!"
  • "What you need is a laser engraver. Perfect for all your projects!"
  • "Replace your soldering iron with our fully featured soldering kit!"
  • "Look at this pocket radiation detector/spectrometer!"
  • "Call us to print your PCBs!"

As if I had a huge workshop and my latest "big project" wasn't "adding a switch to a LED strip". 😅

João Costa shared 7 days ago
João Costa shared 21 days ago

This weekend I was playing a bit with displacement filters, with the help of https://www.smashingmagazine.com/2021/09/deep-dive-wonderful-world-svg-displacement-filtering/

It's actually not that hard to get some cool effects from this. However, it's a bit of a shame that nice distortions require some big gaussian blur kernel... I need to see if I can get similar effects by precomputing the blured images and just blending them with transparency.

GIF
João Costa shared a month ago
João Costa shared a month ago

I've been dusting off my PS2 lately - the DVD player was a goner a long time ago, but with the new PSBBN patches it's trivial to launch some of the old games from an SSD for that nostalgia hit.

One thing that I don't remember being as annoying is the lack of a "Quit" button in games and a "Shutdown" button in the main menu.

I remember finding it odd when the next generation of consoles added a home button (it's not a PC, why would you want to go back to the main menu?), but in hindsight, that's super helpful 😄 .

(I know that there's some homebrew to add a shutdown button to the main menu, but it's kind of useless if I need to reset the console to get back to it)

  • Want to stop playing? Get up!
  • Want to change games? Get up! (To be fair, back then you would have to do that anyway)
  • Want to load a different save file? Get up!
  • Want to change settings? Get up!

Scastie finally supports Scala 3 libraries with Scala.js.🔥

I was playing around with the idea of interactive-ish graphic tutorials: https://scastie.scala-lang.org/JD557/sXkQ2yQsSpqoQgXounejXQ/4

Playing around with Ordered Dithering and Bayer Matrices.

Interactive demo with multiple dithering sizes (2x2, 4x4, 8x8 and 16x16): https://joaocosta.eu/Demos/Dither/

This was much simpler than I thought. The whole dithering logic is just:

def buildBayerMatrix(n: Int): Vector[Vector[Int]] =
  if (n <= 1) Vector(Vector(0))
  else {
    val mn2 = buildBayerMatrix(n / 2) // M_(n/2)

    val q1 = mn2.map(_.map(_ * 4)) // 4*M_(n/2)
    val q2 = q1.map(_.map(_ + 2)) // 4*M_(n/2) + 2*J_(n/2)
    val q3 = q1.map(_.map(_ + 3)) // 4*M_(n/2) + 3*J_(n/2)
    val q4 = q1.map(_.map(_ + 1)) // 4*M_(n/2) + 1*J_(n/2)

    q1.zip(q2).map(_ ++ _) ++ q3.zip(q4).map(_ ++ _)
  }

def buildDitherSurface(n: Int): RamSurface = {
  val mask = buildBayerMatrix(n)
  val max  = n * n
  RamSurface(mask.map(_.map(x => Color.grayscale((x * 255) / max))))
}

def ditherImage(image: Surface, ditherMask: Surface): Surface =
  image.view.zipWith(
    ditherMask.view.repeating,
    (color, mask) =>
      Color(
        if (color.r >= mask.r) 255 else 0,
        if (color.g >= mask.g) 255 else 0,
        if (color.b >= mask.b) 255 else 0
      )
  )
Ordered Dithering Demo joaocosta.eu

More on updates.

This time I wrote an InterIm backend for AthenaEnv.

I also had to work a bit on InterIm's performance to get it to work, as I can't really use Doubles and my text layout algorithm was a bit inneficient. The frame rate still gets a bit choppy when there's a ton of text on screen, but it kind of works.

To test the whole thing, I ported my Quiz game example. This part was quite easy - just had to replace the HTTP calls with hard coded questions/answers and reimplement the RNG (I'm still not sure why scala.util.Random doesn't work... I suspect it's something related to Long math).

However, after testing this for so long on PCSX2, I was quite shocked on how bad things looked on real hardware. I know I'm using a crappy €20 HDMI converter instead of a propper upscaler, but god damn, the text is pretty much unreadable. 😬

Something to keep in mind in the future, I guess.

Lately I've been playing around with getting to run on my (using Scala.js and AthenaEnv, no Scala Native... yet).

I finally got the Minart snake example to run on real hardware with minor modifications to the code (uncap the FPS and read the input from the gamepad).

It does run quite poorly, and it seems to crash if I get an apple, but it's a start, and good enough for a video.

I do have some ideas on how to improve the performance, but it will require a non-trivial amount of work, so I need to build up the courage first. 😅

GIF
João Costa shared 6 months ago
João Costa shared 6 months ago
João Costa shared 6 months ago

Just released an entry for the 32BitJam: Xtreme Skydive 3D!

You can play it in itch.io or check the source code on GitHub: https://github.com/JD557/xtreme-skydive-3d

There's a lot of stuff that could be improved but, while there's still a lot of time in the jam (until Friday), I will be pretty busy next week. Maybe I'll release a post-jam version with some improvements.

Either way, I'm happy that I finally "shipped a 3D game" with my software renderer. 😄

I've been playing the first Jade Cocoon lately - I played that demo a lot when I was younger, but had never played the full game.

It's not the greatest game ever, but I had fun and it didn't overstay it's welcome (~15 hours. I don't have time for long RPGs anymore 😅). I would say it holds up pretty well, especially for a game with tank controls, and the fusion system still remains impressive.

However, I was extremely disappointed with the ending cinematic... It's a low-FPS (with obvious blending between frames) FMV with the in-game character models.

While usually I would be fine with it, this game starts with an incredible animated opening!

I was really expecting that there would be more of that. Although I wouldn't be surprised if that got cut for budget reasons.

It's not easy to show in side-by-side screenshots (as the animation quality makes a big difference) but man, what a downgrade.