<?xml version="1.0" encoding="utf-8"?>
<?xml-stylesheet type="text/xsl" href="../../assets/xml/rss.xsl" media="all"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Mardy (Entratas super Wii)</title><link>http://mardy.it/</link><description></description><atom:link href="http://mardy.it/ia/categories/wii.xml" rel="self" type="application/rss+xml"></atom:link><language>ia</language><copyright>Contents © 2026 &lt;a href="mailto:info@mardy.it"&gt;Alberto Mardegan&lt;/a&gt; </copyright><lastBuildDate>Sat, 11 Apr 2026 13:53:49 GMT</lastBuildDate><generator>Nikola (getnikola.com)</generator><docs>http://blogs.law.harvard.edu/tech/rss</docs><item><title>Teaser: connecting Nintendo Switch controllers to the Wii</title><link>http://mardy.it/ia/blog/2026/04/teaser-connecting-nintendo-switch-controllers-to-the-wii.html</link><dc:creator>Alberto Mardegan</dc:creator><description>&lt;p&gt;A few months ago I started playing with the Bluetooth controller embedded in
the Nintendo Wii, to see if it was possible to get it to connect to other
devices than just the Wii remotes. If you ask internet forums, you might fall
into the impression that the Wii is not using a standard Bluetooth controller,
or that it has been somehow "crippled" in order to restrict it to connect to
the Wiimotes only, but that's not the case: it's an ordinary controller from
its era, it's just that the Wii software (both the official SDK and the
homebrew libogc) only uses it for the Wiimotes.&lt;/p&gt;
&lt;p&gt;I first started looking into
&lt;a href="https://github.com/devkitPro/libogc/tree/master/lwbt"&gt;&lt;code&gt;lwBT&lt;/code&gt;&lt;/a&gt;, the bluetooth
stack used in libogc, but I quickly realized that it was impossible to get full
control over the controller via this library: it has been adapted to work with
the subset of the HID protocol used by the Wiimotes, and even if you can issue
bluetooth commands to the controller via the HCI layer, you cannot receive the
replies, since they are already intercepted by lwBT and there's no way to hook
into them.&lt;/p&gt;
&lt;p&gt;So I started writing my own little bluetooth stack,
&lt;a href="https://github.com/embedded-game-controller/bt-embedded"&gt;&lt;code&gt;bt-embedded&lt;/code&gt;&lt;/a&gt; which
from the ground up has been designed to be used by embedded devices and
covering the use case of serving different clients running in a single process,
and I've integrated it into
&lt;a href="https://github.com/embedded-game-controller/embedded-game-controller"&gt;&lt;code&gt;embedded-game-controller&lt;/code&gt;&lt;/a&gt;
(though this is not merged into the &lt;code&gt;master&lt;/code&gt; branch yet) in order to allow
connecting to bluetooth controllers. And in the last couple of days I've
written a little ugly program to visualize the controllers in a 3D scene, in
order to better test them:&lt;/p&gt;
&lt;iframe src="https://vkvideo.ru/video_ext.php?oid=-230221529&amp;amp;id=456239018&amp;amp;hash=7f8047b16af7164f&amp;amp;hd=1" width="640" height="360" allow="autoplay; encrypted-media; fullscreen; picture-in-picture; screen-wake-lock;" frameborder="0" allowfullscreen&gt;&lt;/iframe&gt;

&lt;p&gt;Yes, the 3D model sucks, it was a nice model when I downloaded it from a free
site, but then heavily reduced the number of polygons using Blender and went a
bit too far; I'll do a better model later. The accelerometer information is not
shown yet (I'd like to use it to actually tilt the controller, instead of using
the joystick), but that will not be hard.&lt;/p&gt;
&lt;p&gt;At the moment, the only supported controllers are the Nintendo Switch Pro
controller (I'm using a clone here) and the Joy-cons, so there's still quite
some work to do to add more.&lt;/p&gt;
&lt;p&gt;It's been a journey in which I learned a lot about Bluetooth and USB and, who
knows, maybe this will come handy in the future too.&lt;/p&gt;</description><guid>http://mardy.it/ia/blog/2026/04/teaser-connecting-nintendo-switch-controllers-to-the-wii.html</guid><pubDate>Sat, 11 Apr 2026 13:13:06 GMT</pubDate></item><item><title>No, libogc did not steal RTEMS code</title><link>http://mardy.it/ia/blog/2025/04/no-libogc-did-not-steal-rtems-code.html</link><dc:creator>Alberto Mardegan</dc:creator><description>&lt;p&gt;&lt;em&gt;Update 09/05/2025:&lt;/em&gt; while the text below addresses a couple of specific blocks of code,
after publishing this article I've been contacted by some people providing more
evidence pointing that the similarity of the code goes beyond what one might
interpret as “inspiration”. There are also a couple of other bits on
information that the reader might want to take into account: first, a
&lt;a href="https://mas.to/@davejmurphy/114414723608693881"&gt;screenshot of an email&lt;/a&gt; in
which Shagkur tells his version of how the code came about (which seems to
point that, if a copyright infringement actually happened, this was done
without the knowledge of devkitPro's maintainers) and a &lt;a href="https://www.rtems.org/news/2025-05-06-rtems-devkit-libogc-response/"&gt;public statement by
RTEMS&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;All of a sudden the Wii homebrew community is in flames after Hector Martin
(&lt;a href="https://github.com/marcan"&gt;marcan&lt;/a&gt;, also known in the Linux Kernel
 community), co-author of “The Homebrew Channel” application, &lt;a href="https://github.com/fail0verflow/hbc"&gt;decided to close
the project&lt;/a&gt; and denounce libogc for its
“theft” of RTEMS's code:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;It has recently been revealed that the threading/OS implementation in libogc is, in fact, stolen from RTEMS. The authors of libogc didn't just steal proprietary Nintendo code, but also saw it fit to steal an open source RTOS and remove all attribution and copyright information. This goes far beyond ignorance about the copyright implications of reverse engineering Nintendo binaries, and goes straight into outright deliberate, malicious code theft and copyright infringement.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;A little below, Hector Martin provides this “proof”: &lt;em&gt;you can compare
&lt;a href="https://github.com/devkitPro/libogc/blob/52c525a13fd1762c10395c78875e3260f94368b5/libogc/lwp_threads.c#L580"&gt;this&lt;/a&gt;
function in libogc to
&lt;a href="https://github.com/atgreen/RTEMS/blob/2f200c7e642c214accb7cc6bd7f0f1784deec833/c/src/exec/score/src/thread.c#L385"&gt;this&lt;/a&gt;
function in a really old version of RTEMS&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;While I don't know the truth about libogc's history (I've started contributing
to it only in the last couple of years), and I'd welcome a first-hand
explanation from shagkur (Michael Wiedenbauer), I can confidently say that the
accusation is unfounded, by just looking at the code. To be more precise: I
cannot vouch for the whole of libogc, I can only say that this function, that
Hector Martin offers as example, actually hints that the code was not stolen.&lt;/p&gt;
&lt;p&gt;While it's obvious that the developer of libogc's code did have a look at
RTEMS's code, and this can be assumed because the variable names are very
similar (and in some cases they are so badly named, that they cannot be this
similar by accident!), the code only looks vaguely similar. Furthermore, for
some reason Hector Martin decided to pick a rather recent version of libogc's
code, but if we look at the &lt;a href="https://github.com/devkitPro/libogc/blob/e550333e6f2fc413fd42d6af9a9aaf036d9de9f6/libogc/lwp_threads.c#L469"&gt;first version that was
committed&lt;/a&gt;
(well, to git, at least), we see that similarities are much less striking.
Let's look at a small snippet of the function, where the thread object's
members are being initialized:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;RTEMS from 1996:&lt;/strong&gt;&lt;/p&gt;
&lt;div class="code"&gt;&lt;pre class="code literal-block"&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;the_thread&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;Start&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;is_preemptible&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;is_preemptible&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;the_thread&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;Start&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;is_timeslice&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;is_timeslice&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;the_thread&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;Start&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;isr_level&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;isr_level&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;the_thread&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;current_state&lt;/span&gt;&lt;span class="w"&gt;          &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;STATES_DORMANT&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;the_thread&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;resource_count&lt;/span&gt;&lt;span class="w"&gt;         &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;the_thread&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;real_priority&lt;/span&gt;&lt;span class="w"&gt;          &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;priority&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;the_thread&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;Start&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;initial_priority&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;priority&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;libogc from 2023:&lt;/strong&gt;&lt;/p&gt;
&lt;div class="code"&gt;&lt;pre class="code literal-block"&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;thethread&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;budget_algo&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;prio&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="mi"&gt;128&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;?&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;LWP_CPU_BUDGET_ALGO_NONE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;LWP_CPU_BUDGET_ALGO_TIMESLICE&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;thethread&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;is_preemptible&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;is_preemtible&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;thethread&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;isr_level&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;isr_level&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;thethread&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;real_prio&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;prio&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;thethread&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;cur_state&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;LWP_STATES_DORMANT&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;thethread&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;cpu_time_budget&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;_lwp_ticks_per_timeslice&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;thethread&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;suspendcnt&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;thethread&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;res_cnt&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;libogc from before 2004:&lt;/strong&gt;&lt;/p&gt;
&lt;div class="code"&gt;&lt;pre class="code literal-block"&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;thethread&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;isr_level&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;isr_level&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;thethread&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;real_prio&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;prio&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;thethread&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;cur_state&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;LWP_STATES_DORMANT&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;thethread&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;suspendcnt&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;thethread&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;res_cnt&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Let's pay attention to the &lt;code&gt;is_preemtible&lt;/code&gt; variable, which is present in
current's libogc and in RTEMS, but not in the old libogc: it was added later.
Now, RTEMS has it since at least 1996, so, if libogc was actually copied from
it, how come this variable was not copied, too, but added at a later time?
Note, the accusation against libogc has been formulated in clear-cut terms:
&lt;em&gt;...steal an open source RTOS and remove all attribution and copyright
information...&lt;/em&gt;; it's clear that this is not what happened. It's much more
likely that libogc's developers did look at RTEMS code (which at that time
&lt;a href="https://github.com/atgreen/RTEMS/blob/2f200c7e642c214accb7cc6bd7f0f1784deec833/LICENSE"&gt;had another
license&lt;/a&gt;
and was known as the &lt;em&gt;Real Time Executive for Missile Systems&lt;/em&gt; or &lt;em&gt;Real Time
Executive for Military Systems&lt;/em&gt;) as a model and source of information, but
since the code was heavily adapted for libogc, they didn't feel they were
creating a “derivative work”. It's a grey area, but even myself, if I took a
project written in C++ and translated it into Rust or C#, for example, I'm
rather sure I wouldn't consider my work to be a derivative of the original; I'm
not a lawyer, so I might be plain wrong here, but I would be in good faith.&lt;/p&gt;
&lt;p&gt;At most, libogc could be accused of plagiarism, but in my humble opinion even
that would be a stretch: since we are not talking of some artistic work, but of
work of science/ingeneering, it's normal to build upon others' work. Yes,
credit should generally be given, but given that we are talking of a US
military-related project, I can see that there could be ethical reasons for not
wanting to do so.&lt;/p&gt;
&lt;h4&gt;Summing up&lt;/h4&gt;
&lt;p&gt;I'm consciously omitting the other old accusations about “stealing” Nintendo's
code, first because they are not new, and secondly because I don't consider
reverse-engineering as stealing. What I found most disturbing about this story
is that it smells hatred from far away, since I have a hard time to understand
why someone felt the need to look into libogc's origin and publicly smearing
the project and ultimately harming the whole of the Wii homebrew community.&lt;/p&gt;</description><guid>http://mardy.it/ia/blog/2025/04/no-libogc-did-not-steal-rtems-code.html</guid><pubDate>Mon, 28 Apr 2025 13:56:49 GMT</pubDate></item><item><title>Porting OpenGL games to the Nintendo Wii: chro.mono</title><link>http://mardy.it/ia/blog/2025/04/porting-opengl-games-to-the-nintendo-wii-chomono.html</link><dc:creator>Alberto Mardegan</dc:creator><description>&lt;p&gt;More than one year has passed since my last blog post, and I'm a bit ashamed to
confess that today's post is again about porting games to the Nintendo Wii — I
always tell to myself that I'm soon going to move to something else, possibly
less geeky than this (by the way, there &lt;em&gt;is&lt;/em&gt; something else I could write
about, but I'll leave it for another post!), but the problems posed by porting
games to an old console are just way too stimulating, and my brain gets
attracted to them in a way that I cannot resist.&lt;/p&gt;
&lt;p&gt;Anyway, have you ever heard of &lt;a href="https://github.com/devkitPro/opengx"&gt;OpenGX&lt;/a&gt;?
It's a project aiming to write an OpenGL driver for the Nintendo GameCube and
Wii's GX API: while these consoles have good (at the time, at least) 3D
capabilities, they were programmed via an API not even remotely close to
OpenGL, so back in 2013 one developer by the name of David Guillen Fandos
started a project to investigate the possibility of wrapping the GX API in
OpenGL. The project was abandoned after reaching a very basic state, but it's
author was diligent enough to write a &lt;a href="https://github.com/davidgfnet/opengx/blob/master/doc/opengx.pdf"&gt;PDF
file&lt;/a&gt;
describing its design and some implementation details. Having bumped into this
document, I was inspired by it and felt it was a pity that such a project had
died -- especially given the fact that this didn't happen because of some
technical infeasibility. So exactly one year ago, in the spring of 2024, I
picked it up and tried porting the game BillardGL to the Wii; I had to add
quite a few things to OpenGX, and adjusting the lighting pipeline, but after
less than one month &lt;a href="https://github.com/mardy/billardgl/tree/wii-port"&gt;the port of BillardGL was
ready&lt;/a&gt;. In the following
months, I ported several other OpenGL 1.x games, gradually enhancing and
expanding OpenGX, until I got most of OpenGL 1.4 supported.&lt;/p&gt;
&lt;center&gt;
&lt;figure&gt;
  &lt;a href="http://mardy.it/archivos/imagines/blog/billardgl.png"&gt;&lt;img src="http://mardy.it/archivos/imagines/blog/billardgl.png" width="80%"&gt;&lt;/a&gt;
  &lt;figcaption&gt;A 23 year old game was just ported to a 19 year old console.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/center&gt;

&lt;p&gt;Should I have stopped there? Probably. Because indeed the Wii's GPU, despite
allowing a good degree of complexity in setting up its shading engine (called
TEV, Texture Environment), does not support the modern GL shading language, and
trying to have the CPU compile the shaders into something that GX could
understand is a task doomed to fail, in part because this would eat up all the
computing power, but especially because there simply isn't an algorithm that
could translate GLSL into GX commands. Is this the end of the journey then?&lt;/p&gt;
&lt;p&gt;Well, the fact that OpenGL 2.0+ shaders can not be machine-translated into GX
commands does not mean that this task is impossible: we've still got the human
brain to use! The idea is the following: let the deveoper who is porting the
game write the GX code corresponding to the GLSL code by hand. Saying it like
this might feel like this is no better than saying “Just port the whole
rendering backend to GX!” but as a matter of facts, there's a big difference:
with this approach all the rest of the OpenGL code stays untouched, and the way
I have design this &lt;em&gt;shader substitution&lt;/em&gt; to work in OpenGX allows one to keep
the GX code isolated in its own source file, without having to change a single
line of the program, save from adding a line near the beginning (in &lt;code&gt;main()&lt;/code&gt;,
typically) to install the GX hooks. This means that your program will still
call &lt;code&gt;glUniform*()&lt;/code&gt;, &lt;code&gt;glVertexAttribPointer()&lt;/code&gt; and so on to setup the rendering
pipeline, but when the program will get to execute &lt;code&gt;glDrawArrays()&lt;/code&gt; OpenGX will
pass control to the hooks previously installed, which will receive the uniforms
and the attributes, and setup the pipeline using GX commands. It might seem
complicated, but &lt;a href="https://github.com/devkitPro/opengx/commit/f837fe9bd6b363bb6a33f298eae99f15e0cd8bfe"&gt;it really
isn't&lt;/a&gt;
(well, if you can deal with the GX API), and it's even more efficient than the
fixed pipeline of OpenGL 1.x, since here the GX commands are reduced to the
bare minimum required by the shader, whereas in the fixed pipeline we have to
follow predefined steps.&lt;/p&gt;
&lt;center&gt;
&lt;figure&gt;
&lt;iframe src="https://vkvideo.ru/video_ext.php?oid=-230221529&amp;amp;id=456239017&amp;amp;hd=1" width="640" height="360" allow="autoplay; encrypted-media; fullscreen; picture-in-picture; screen-wake-lock;" frameborder="0" allowfullscreen&gt;&lt;/iframe&gt;
  &lt;figcaption&gt;chro.mono running on a Nintendo Wii.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/center&gt;

&lt;p&gt;The first (and for the time being, the last) OpenGL 2.0+ game I've ported to
the Wii is &lt;a href="https://thp.io/2013/chromono/"&gt;chro.mono&lt;/a&gt;, a nice puzzle game from
2013 whose source code has been released in 2021. It uses the FBO feature from
OpenGL 3.0, so I had to implement it in OpenGX as well. I'm quite satisfied
with the result, not only because the game runs at 60 FPS, but because it shows
how rather complex shaders (the game has more than a dozen of them) can be
realized in GX; to tell the truth, in couple of cases I had to implement the
fragment shader by converting its code to C and drawing to a temporary texture,
but luckily these shaders are used only during program startup to draw to an
FBO and don't negatively affect the game performance. You can download it &lt;a href="https://github.com/mardy/chromono/releases"&gt;from
here&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Summing up, if you get really bored and would like to engage in something
unusual (read: useless), porting games to older consoles would definitely keep
you active for some time. Unfortunately there aren't that many OpenGL games
which are open source, so the candidates for porting are not that many (by the
way, feel free to suggest in the comments — well, not for me, but maybe
&lt;em&gt;someone else&lt;/em&gt; will do it).&lt;/p&gt;</description><guid>http://mardy.it/ia/blog/2025/04/porting-opengl-games-to-the-nintendo-wii-chomono.html</guid><pubDate>Tue, 22 Apr 2025 15:35:25 GMT</pubDate></item><item><title>libSDL2 and VVVVVV for the Wii</title><link>http://mardy.it/ia/blog/2024/02/libsdl2-and-vvvvvv-for-the-wii.html</link><dc:creator>Alberto Mardegan</dc:creator><description>&lt;p&gt;Just a quick update on something that I've been working on in my free time.&lt;/p&gt;
&lt;p&gt;I recently refurbished my old Nintendo Wii, and for some reason I cannot yet
explain (not even to myself) I got into homebrew programming and decided to
port libSDL (the 2.x version -- a 1.x port already existed) to it. The result
of this work is already available via the &lt;a href="https://devkitpro.org/"&gt;devkitPro&lt;/a&gt;
distribution, and although I'm sure there are still many bugs, it's overall
quite usable.&lt;/p&gt;
&lt;p&gt;In order to prove it, I ported the game &lt;a href="https://thelettervsixtim.es/"&gt;VVVVVV&lt;/a&gt;
to the Wii:&lt;/p&gt;
&lt;iframe src="https://vk.com/video_ext.php?oid=7200355&amp;amp;id=456239302&amp;amp;hd=1" width="640" height="360" allow="autoplay; encrypted-media; fullscreen;
picture-in-picture;" frameborder="0" allowfullscreen&gt;&lt;/iframe&gt;

&lt;p&gt;During the process I had to fix quite a few bugs in my libSDL port and in a
couple of other libraries used by VVVVVV, which will hopefully will make it
easier to port more games. There's still an issue that bothers me, where the
screen resolution seems to be not totally supported by my TV (or is it the HDMI
adaptor's fault?), resulting in a few pixels being cut at the top and at the
bottom of the screen. But unless you are a perfectionist, it's a minor issue.&lt;/p&gt;
&lt;p&gt;In case you have a Wii to spare, or wouldn't mind playing on the Dolphin
emulator, &lt;a href="https://github.com/mardy/VVVVVV/releases/tag/v2.4.1_wii1"&gt;here's the link to the VVVVVV
release&lt;/a&gt;. Have fun! :-)&lt;/p&gt;</description><guid>http://mardy.it/ia/blog/2024/02/libsdl2-and-vvvvvv-for-the-wii.html</guid><pubDate>Fri, 02 Feb 2024 17:50:44 GMT</pubDate></item></channel></rss>