Grid Sage Forums

Grid Sage Forums

  • November 21, 2024, 08:34:54 PM
  • Welcome, Guest
Please login or register.

Login with username, password and session length
Advanced search  

News:

LINKS: Website | Steam | Wiki

Author Topic: [Feature Request] Embedding additional data  (Read 4617 times)

izzy

  • Unaware
  • *
  • Supported Cogmind Alpha Access 2015-2017 (Prime Tier)
  • Posts: 16
    • View Profile
[Feature Request] Embedding additional data
« on: February 08, 2019, 04:43:34 AM »

Hi!

Actually I would like to request two features. One, to add some kind of EXIF data to rex paint files, with at least author name, copyright and notes.

Second feature I would like to request is that when you click on any glyph, you see 1 or more input fields somewhere on tool window. They you can edit those data, and save them ofc. It would be just carrier of addition information for the given tile. I have some mochup ASCII art, and there I have for example the torches. With this data I could design radius of the torch and embed it into rex file. This is just one example, but the possibilities are endless. Spawning points with ID-s or enemies, setting the randomness of the certain tiles etc etc.

Thanks in advance

Logged

Kyzrati

  • Administrator
  • True Cogmind
  • *****
  • Posts: 4477
    • View Profile
    • Cogmind
Re: [Feature Request] Embedding additional data
« Reply #1 on: February 08, 2019, 05:05:11 AM »

Hi izzy, yeah this is something I've thought about for a very long time, since the earliest versions, but felt like there are too many possible implementations and users have so many different needs and many can't be met. In the end it seems like a better solution is to do as many REXPaint devs do and define a partner file for a given .xp, which contains additional info in any amount/layout/format/whatever is convenient for the user and their specific purpose.

Layers come in real handy here, adding identifiers to additional image layers and referencing those in your code and/or external files (this is how myself and others achieve this effect).

This feature has been on my potential todo list for years now, and it's still there, but I dunno... If anything it'd be something to consider for 2.0, but there are a bunch of more widely valuable and effective features to work on before something like that.

As for the more basic additional info, it could happen eventually, though I'm loath to update the .xp format since I really like how simple it is, plus we have so much existing reader code out there that depends on the old format.
Logged
Josh Ge, Developer - Dev Blog | @GridSageGames | Patreon

gumix

  • Cyborg
  • ***
  • Posts: 134
    • View Profile
Re: [Feature Request] Embedding additional data
« Reply #2 on: February 10, 2019, 04:53:41 AM »

Yep, that is something I requested years ago, bu indeed handling all users needs in that way would be hardly possible, especially when it comes to convenient editting of such data.

So personally, I'd rather like to start initiative for adding plugin API. In the first place it could simply add save and load functions handling custom file formats. I can understand that it could begin even bigger flood of requests asking you to add something to the plugin API, which I guess you'd like to avoid :P
Logged

Kyzrati

  • Administrator
  • True Cogmind
  • *****
  • Posts: 4477
    • View Profile
    • Cogmind
Re: [Feature Request] Embedding additional data
« Reply #3 on: February 10, 2019, 05:45:54 AM »

Heh, and not even just gumix :P. I've got a list of people who've requested this one, but yeah I don't see how it could work well, since each of you would benefit from a slightly different implementation... The external solution is the most flexible!

I'm not really sure how to handle an API--that'd be beyond my skills anyway xD. At this point one might say another route is to open source it, but that, too, would have some negative side effects and isn't something I want to do.

I will certainly continue improving it, though :)

Hope I don't open some can of worms by asking, but... on the simple end how does one even go about implementing an API for saving/loading? And how do others use it? (Of course, without even knowing the answer I can definitely see how starting an initiative like this would result in that flood... I rather like the status quo, where we already have a bunch of external readers/writers in many languages and devs just use those to interface with their own games and software.)
Logged
Josh Ge, Developer - Dev Blog | @GridSageGames | Patreon

gumix

  • Cyborg
  • ***
  • Posts: 134
    • View Profile
Re: [Feature Request] Embedding additional data
« Reply #4 on: February 10, 2019, 08:02:34 AM »

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:

Code: [Select]
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 :)

Code: [Select]

#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!


« Last Edit: February 10, 2019, 11:57:02 AM by gumix »
Logged

Kyzrati

  • Administrator
  • True Cogmind
  • *****
  • Posts: 4477
    • View Profile
    • Cogmind
Re: [Feature Request] Embedding additional data
« Reply #5 on: February 10, 2019, 04:44:55 PM »

Wow, thanks a lot for sharing this, gumix, it is pretty clear. Though I guess this means the plugin must be written in C unless the API provides support for other languages? Seems a lot more limiting than the current situation given that RP users use such a wide variety of languages. I don't see a whole lot being gained by users doing it this way when the same effect can be achieved externally, with greater flexibility.
Logged
Josh Ge, Developer - Dev Blog | @GridSageGames | Patreon

gumix

  • Cyborg
  • ***
  • Posts: 134
    • View Profile
Re: [Feature Request] Embedding additional data
« Reply #6 on: February 11, 2019, 05:27:17 AM »

You're welcome.
Though I guess this means the plugin must be written in C unless the API provides support for other languages?
Yes and not. C of course is supported, C++ can do it by simply adding extern "C" (like in examlpe), other languages would require gluing dll.

I don't see a whole lot being gained by users doing it this way when the same effect can be achieved externally, with greater flexibility.
Yea, I can understand you. 'File interface' is absolutely fine and universal. Any format conversion can be done by external toolchain of readers, metadata injectors and writers. So real reason for plugin interface is not just to have R/W functionality. In example. for me it is essential to be able to provide custom blending modes to rex. Could be in form of:

Code: [Select]
bool RegisterBlendMode(const char* name, Cell (*BlendFunc)(Cell* above, Cell* below))
You could probably notice that all my work used pretty different layer blending from what rex displays in editor. Painting content for my isometry game prototype was so painful (just because of 'depth' blending) I have paused it until I find alternative way for doing it. So here's a chance for me to still use my fav rex :)

Logged

Kyzrati

  • Administrator
  • True Cogmind
  • *****
  • Posts: 4477
    • View Profile
    • Cogmind
Re: [Feature Request] Embedding additional data
« Reply #7 on: February 11, 2019, 05:37:42 AM »

I see, thanks for providing another sample use case. Yeah layer blending is not something REXPaint is even capable of yet, though it's actually been on the long-term TODO list for a while... It's the kind of thing that would make more sense for 2.0 with a UI overhaul (and would also require have a more involved file format! :/).
Logged
Josh Ge, Developer - Dev Blog | @GridSageGames | Patreon

gumix

  • Cyborg
  • ***
  • Posts: 134
    • View Profile
Re: [Feature Request] Embedding additional data
« Reply #8 on: February 11, 2019, 05:48:19 AM »

 
Code: [Select]
´´´´´´´´´´´´´´´´´´´´´´´¶¶¶¶¶¶¶¶
´´´´´´¶¶¶¶¶´´´´´´´´¶¶¶¶´´´´´´´´¶¶¶¶
´´´´´¶´´´´´¶´´´´¶¶´´´´´´´´´´´´´´´´´´¶¶
´´´´´¶´´´´´¶´´´¶¶´´´´´´¶¶´´´´¶¶´´´´´´´¶¶
´´´´´¶´´´´¶´´¶¶´´´´´´´´¶¶´´´´¶¶´´´´´´´´¶¶
´´´´´´¶´´´¶´´´¶´´´´´´´´´´´´´´´´´´´´´´´´´¶¶
´´´´¶¶¶¶¶¶¶¶¶¶¶¶´´´´´´´´´´´´´´´´´´´´´´´´´¶¶
´´´¶´´´´´´´´´´´´¶´´´¶¶´´´´´´´´´´´¶¶´´´´´´¶¶
´´¶¶´´´´´´´´´´´´¶´´´¶¶´´´´´´´´´´´¶¶´´´´´´¶¶
´¶¶´´´¶¶¶¶¶¶¶¶¶¶¶´´´´´¶¶´´´´´´´¶¶´´´´´´´¶¶
´¶´´´´´´´´´´´´´´´¶´´´´´´¶¶¶¶¶¶¶´´´´´´´´¶¶
´¶¶´´´´´´´´´´´´´´¶´´´´´´´´´´´´´´´´´´´´¶¶
´´¶´´´¶¶¶¶¶¶¶¶¶¶¶¶´´´´´´´´´´´´´´´´´´´¶¶
´´¶¶´´´´´´´´´´´¶´´´¶¶¶¶´´´´´´´´´¶¶¶¶
´´´¶¶¶¶¶¶¶¶¶¶¶¶´´´´´´´´¶¶¶¶¶¶¶¶¶
Logged

izzy

  • Unaware
  • *
  • Supported Cogmind Alpha Access 2015-2017 (Prime Tier)
  • Posts: 16
    • View Profile
Re: [Feature Request] Embedding additional data
« Reply #9 on: February 15, 2019, 04:26:08 AM »

Thanks for reply. Plugins are also welcome :) I could achieve the same result with writing the plugin for it. I thought about adding additional data in layers, but I somehow don't like that idea. I need to think about it :)
Logged

gumix

  • Cyborg
  • ***
  • Posts: 134
    • View Profile
Re: [Feature Request] Embedding additional data
« Reply #10 on: February 15, 2019, 10:54:37 AM »

Personally I've ended up with solution of extended image canvas by 1 row (in every .xp). So I was able to paint there arbitrary metadata on per leyer basis. Of course you may need 2 or more rows depending on your data volume :)
Logged

Kyzrati

  • Administrator
  • True Cogmind
  • *****
  • Posts: 4477
    • View Profile
    • Cogmind
Re: [Feature Request] Embedding additional data
« Reply #11 on: February 15, 2019, 05:48:30 PM »

Ah yeah that's a really cool idea, too... I imagine one could even expand the number of columns and make data/comments about particular rows in certain uses cases, too.

In some situations I essentially take this approach further by including lots and lots of different objects/layouts/whatevers in a single .xp file (on one layer is fine), and use the space between them to add more data, either just for outside reference or to help define the object for the game. But the file is read and dissected by the game at run time all the same. Just gotta get creative :D
Logged
Josh Ge, Developer - Dev Blog | @GridSageGames | Patreon

Joshua

  • Sigix
  • ****
  • Bug Hunter Weekly Seed Participant Shared a Confirmed Combat Win Shared a Confirmed Stealth Win
  • Posts: 319
    • View Profile
Re: [Feature Request] Embedding additional data
« Reply #12 on: February 18, 2019, 03:49:41 AM »

I am not a REXPaint user nor likely to be one so take my thoughts on API design for what they're worth in that regard.

Here is a sketch of an alternate approach I thought of:

A text-based message protocol - you could set in a configuration file another program for rexpaint to launch on startup with localhost:port to plug into.

Messages from rexpaint could map more or less to commands in the UI, or be responses to messages from the plugin.

One way to do this without super tricky async coding would be to invert the flow of control by having the plugin initially, and after it's done processing every time, send a LISTEN message back to rexpaint which tells rexpaint to start its main loop back up, so that every exchange in the protocol starts with a message from the plugin.

I imagine things like

Code: [Select]
LISTEN // wait until next message from REXPaint
LOAD filename // tell REX to load the file
SAVE filename // tell REX to save the file
GET layer // return an entire layer to the plugin in rexpaint format
GET layer x y w h // return part of a layer
BLIT layer x y w h // followed by image data in rexpaint format, to blit onto that part of the image
CMD name // for custom-mapped keybindings: something like `key a plugin-command=tag`. The plugin could be whatever it wanted with this
// including popping up Windows UI over rexpaint to take user input

This is just a sketch, I'm sure other details could be fleshed out if this approach seems worthwhile.
Logged