Ok, I'll try to make it as short as possible, so it may appear to be a bit silly. But this is just to give you an idea how plugins could interact with rex.
When Rex starts up, it looks for files ie: *.xplug in its ./plugins directory. For each of them:
- it tries to load it as dll using HMODULE LoadLibrary(<path>);
- if loaded, rex should check if indeed it is its plugin checking for exported function, ie: GetProcAddress(HMODULE, "RexPluginInit");
- if it returns a pointer to a function, rex should call it.
What arguments RexPluginInit function takes and what result it returns should be defined by you in some redistributed plugin api header.
Let's assume plugins should interface with rex using C linkage, your header named "rex_plug_api.h" would look like this:
struct Cell
{
uint8_t fg_rgb[3], bg_rgb[3];
uint32_t chr_code;
};
struct RexAPI
{
int version;
// pointer to function (implemented by rex) that can be called by plugin at its startup (from its implementation of RexPluginInit)
// rex should keep all registered formats somewhere and make it possible to choose such format during export / import
bool (*RegisterFileFormat)(const char* file_ext, bool (*Save)(const char* path), bool (*Load)(const char* path));
// pointers to functions (implemented by rex) intented to be called during saving
int (*GetNumLayers)();
int (*GetLayerWidht(int layer);
int (*GetLayerHeight(int layer);
bool (*GetLayerData(int layer, Cell* c);
// pointers to functions (implemented by rex) intented to be called during loading
bool (*AddLayer)(int layer, int width, int height);
bool (*SetLayerData)(int layer, const Cell* data);
// version 1 ends here ------------------------------------
// followed by extended api in future
// ...
};
extern "C" bool RexPluginInit( RexAPI* plugin_api );
So now let's try to implement sample custom format loader/saver plugin, which is almost identical to .xp format, except gzip usage and column/row order
#include "rex_plug_api.h"
#include <stdio.h>
#include <malloc.h>
RexAPI* api = 0;
bool MySave(const char* path)
{
FILE* f=fopen(path,"wb");
if (!f)
return false;
int layers = api->GetNumLayers();
fwrite(&layers,1,sizeof(int),f);
for (int i=0; i<layers; i++)
{
int w = api->GetLayerWidth(i);
int h = api->GetLayerHeight(i);
fwrite(&w,1,sizeof(int),f);
fwrite(&h,1,sizeof(int),f);
int n =w*h;
Cell* data = (Cell*)malloc(sizeof(Cell) * n);
api->GetLayerData(i,data);
fwrite(data, n, sizeof(Cell), f);
free(data);
}
fclose(f);
return true;
}
bool MyLoad(const char* path)
{
FILE* f=fopen(path,"rb");
if (!f)
return false;
int layers;
fread(&layers,1,sizeof(int),f);
for (int i=0; i<layers; i++)
{
int w,h;
fread(&w,1,sizeof(int),f);
fread(&h,1,sizeof(int),f);
api->AddLayer(i,w,h);
int n = w*h;
Cell* data = malloc(sizeof(Cell)*n);
fread(data,n,sizeof(Cell),f);
api->SetLayerData(i,data);
free(data);
}
fclose(f);
return true;
}
bool RexPluginInit( RexAPI* plugin_api )
{
api = plugin_api;
if (api->version < 1)
return false;
api->RegisterFileFormat(".myext", MySave, MyLoad);
return true;
}
That's it, I hope everything is clear, although I didn't try to compile it, so certainly there are typos.
I'd love to help moving this initiative forward!