-- Leo's gemini proxy

-- Connecting to republic.circumlunar.space:1965...

-- Connected

-- Sending request

-- Meta line: 20 text/gemini

🕹 Embedding Wren, pt2


It's Xmas time, which, amongst other things, means I have no guilt about working on the side project for a few days...


So I'm back on the EH500!


The last time I picked this up was in the Summer, so I decided to finish embedding Wren and get the rest of the "console" exposed to script.


Changes to Initialise and Tick


When I last discussed this, I posted an example where I loaded a class of static methods and ticked those. I've changed tack since then in two fundamental ways.


First, a class of static methods is limited in what it can operate on (static members), so now I instantiate the class and adjust my call handles appropriately:


{
   wrenEnsureSlots(s_pWrenVM, 1);
   wrenSetSlotHandle(s_pWrenVM, 0, s_pWH_LevelMode_ClassHandle);

   //
   // Call new()
   //
   wrenCall(s_pWrenVM, s_pWH_New);

   wrenReleaseHandle(s_pWrenVM, s_pWH_LevelMode_ClassHandle);
   s_pWH_LevelMode_ClassHandle = NULL;

   if (wrenGetSlotCount(s_pWrenVM) == 0)
   {
      LOG_ERROR("-- Interpreter error, calling LevelMode->new");
      Framework_Guru(SCRIPT_ERROR);
   }
   s_pWH_LevelMode_ClassHandle = wrenGetSlotHandle(s_pWrenVM, 0);
}

The instantiated class is free to create other objects, hold a list of things to tick, etc. which was what I needed all along.


Secondly, in the Summer, the platform API -- the foreign methods that map to console "registers" and functions in C-land -- was on disk, in its own module, that others could import. I didn't like this. So I've stolen a trick from the Wren implementation in Tic80; it's trivial to store the API in a string, in C code, and load it into VM as the first thing that's parsed, before I do any of the above.


static char const* s_sPlatformAPI = "\n\
class EH {\n\
   construct new() {}\n\
   foreign static GetFrameCount()\n\
   foreign static GetGameDeltaSeconds()\n\
...
   static TO_RADIANS { 0.0174532925 }\n\
   static TO_DEGREES { 57.295779514 }\n\
   static PI { 3.1415926535 }\n\
   static SCREEN_WIDTH { 384 }\n\
   static SCREEN_HEIGHT { 216 }\n\
   static SCREEN_HALF_WIDTH { 192 }\n\
   static SCREEN_HALF_HEIGHT { 108 }\n\
\
}\n"

This has the effect of adding a class full of static methods into module "main", making them accessible anywhere via an import:


import "main" for EH

From the scripting perspective, this makes no difference, but it removes the need for a source file on disk that could go missing or get out of sync with the EH500.


Kicking the Tyres


https://tdi.online/images/eh500_xmas.mp4


Bar palette manipulation, I have everything in the EH500 exposed to Wren. It's been quick to implement -- little more than a day -- and easy enough to test. The slot system is clean, simple and fits my needs perfectly.


It's taken me a while to grok the error messages from the interpreter, but that's no different than any other language... I just need to use it in anger.


Next steps:

Add a math library (just the basics, with some vector stuff)

Add easing functions (ease all the things!)

Decide how I'm going to do the collision detection...

Add some audio!




-- Response ended

-- Page fetched on Fri May 3 09:13:05 2024