<html><head><meta http-equiv="content-type" content="text/html; charset=us-ascii"></head><body style="overflow-wrap: break-word; -webkit-nbsp-mode: space; line-break: after-white-space;"><div>Hello,</div><div><br></div><div>Regarding FFI with C, I have some questions regarding the method I am using to</div><div>manage a particular data value. I am writing a graphics program using a</div><div>library called raylib, it's a break from my usual party with SDL2, and I am</div><div>finding this library to be much more effective in terms of less code to get</div><div>things running.</div><div><br></div><div>However, I am now finding myself running into the same issues again and again</div><div>and it revolves around managing colours. The structure that defines a Color is</div><div>this:</div><div><font face="APL385"><br></font></div><div><font face="APL385">    // Color, 4 components, R8G8B8A8 (32bit)</font></div><div><font face="APL385">    typedef struct Color {</font></div><div><font face="APL385">        unsigned char r;        // Color red value</font></div><div><font face="APL385">        unsigned char g;        // Color green value</font></div><div><font face="APL385">        unsigned char b;        // Color blue value</font></div><div><font face="APL385">        unsigned char a;        // Color alpha value</font></div><div><font face="APL385">    } Color;</font></div><div><br></div><div>The author says that he uses 'pass by value' in most of the function calls, as</div><div>he has deliberately designed them to be no more than 64 bits, 32 bits for the</div><div>colours though, a typical C library signature to demonstrate:</div><div><br></div><div><font face="APL385">    DrawRectangle(int posX, int posY, int width, int height, Color color);</font></div><div><br></div><div>He also has, conveniently, predefined a whole bunch of colours as a default</div><div>palette like this:</div><div><font face="APL385"><br></font></div><div><font face="APL385">    #define LIGHTGRAY  CLITERAL(Color){ 200, 200, 200, 255 }   // Light Gray</font></div><div><font face="APL385">    #define GRAY       CLITERAL(Color){ 130, 130, 130, 255 }   // Gray</font></div><div><font face="APL385">    #define DARKGRAY   CLITERAL(Color){ 80, 80, 80, 255 }      // Dark Gray</font></div><div><font face="APL385">    :</font></div><div><br></div><div>The only real way I could find to model that in Mercury has been to literally</div><div>re-invent the weel and create this union type and then some helpers:</div><div><br></div><div><font face="APL385">    :- type p_color</font></div><div><font face="APL385">        --->    lightgray</font></div><div><font face="APL385">        ;       gray</font></div><div><font face="APL385">        ;       yellow</font></div><div><font face="APL385">        :</font></div><div><font face="APL385">        ;       raywhite. % FInal colour from header file palette</font></div><div><font face="APL385"><br></font></div><div><font face="APL385">    :- type color</font></div><div><font face="APL385">        --->    rgb(uint8, uint8, uint8)</font></div><div><font face="APL385">        ;       rgba(uint8, uint8, uint8, uint8)</font></div><div><font face="APL385">        ;       c(p_color).</font></div><div><br></div><div>This means that so far, for a mainl loop that looks like this:</div><div><br></div><div><br></div><div><div><font face="APL385">:- pred run_loop(io::di, io::uo) is det.</font></div><div><font face="APL385"><br></font></div><div><font face="APL385">run_loop(!IO) :-</font></div><div><font face="APL385">    window_should_close(X, !IO),</font></div><div><font face="APL385">    (</font></div><div><font face="APL385">        X = yes,</font></div><div><font face="APL385">        trace_log("Stopped by user", [], !IO)</font></div><div><font face="APL385">    ;</font></div><div><font face="APL385">        X = no,</font></div><div><font face="APL385"><br></font></div><div><font face="APL385">        dropped_files(Files, !IO),</font></div><div><font face="APL385"><br></font></div><div><font face="APL385">        begin_drawing(!IO),</font></div><div><font face="APL385"><br></font></div><div><font face="APL385">            clear_background(c(beige), !IO),</font></div><div><font face="APL385">            draw_fps(0, 0, !IO),</font></div><div><font face="APL385"><br></font></div><div><font face="APL385">            ui_draw(new_cursor(100,100), !IO),</font></div><div><font face="APL385"><br></font></div><div><font face="APL385">        end_drawing(!IO),</font></div><div><font face="APL385"><br></font></div><div><font face="APL385">        ( if list.is_not_empty(Files) then</font></div><div><font face="APL385">            io.write_list(Files, "\n", io.print_line, !IO)</font></div><div><font face="APL385">        else</font></div><div><font face="APL385">            true</font></div><div><font face="APL385">        ),</font></div><div><font face="APL385">        run_loop(!IO)</font></div><div><font face="APL385">    ).</font></div></div><div><br></div><div>I have to write a predicate that takes in the 'color', breaks it into RGBA</div><div>uint8 values and then calls the C wrapper:</div><div><br></div><div><br></div><div><font face="APL385">draw_rectangle(X, Y, W, H, COLOR, !IO) :-</font></div><div><font face="APL385">    color_parts(COLOR, R, G, B, A),</font></div><div><font face="APL385">    draw_rectangle_(X, Y, W, H, R, G, B, A, !IO).</font></div><div><font face="APL385"><br></font></div><div><font face="APL385">:- pred draw_rectangle_(</font></div><div><font face="APL385">    int::in, int::in, int::in, int::in,</font></div><div><font face="APL385">    uint8::in, uint8::in, uint8::in, uint8::in,</font></div><div><font face="APL385">    io::di, io::uo</font></div><div><font face="APL385">) is det.</font></div><div><font face="APL385"><br></font></div><div><font face="APL385">:- pragma foreign_proc(</font></div><div><font face="APL385">    "C", draw_rectangle_(</font></div><div><font face="APL385">        X::in, Y::in, W::in, H::in,</font></div><div><font face="APL385">        R::in, G::in, B::in, A::in,</font></div><div><font face="APL385">        _IO0::di, _IO::uo</font></div><div><font face="APL385">    ),</font></div><div><font face="APL385">    [ promise_pure, will_not_call_mercury, will_not_throw_exception</font></div><div><font face="APL385">    , will_not_modify_trail, thread_safe, does_not_affect_liveness</font></div><div><font face="APL385">    , tabled_for_io],</font></div><div><font face="APL385">    "</font></div><div><font face="APL385">        Color C = {R, G, B, A};</font></div><div><font face="APL385">        DrawRectangle(X, Y, W, H, C);</font></div><div><font face="APL385">    ").</font></div><div><br></div><div>You can see that the first thing I have to do before calling the</div><div>DrawRectangle() API call is to recompose the uint8-s back into a 32 bit value!</div><div><br></div><div><br></div><div>Predicate color_parts/5 is defined as:</div><div><br></div><div><font face="APL385">:- pred color_parts(</font></div><div><font face="APL385">    color::in, uint8::out, uint8::out, uint8::out, uint8::out</font></div><div><font face="APL385">) is det.</font></div><div><font face="APL385"><br></font></div><div><font face="APL385">color_parts(rgb(R,G,B), R, G, B, 255u8).</font></div><div><font face="APL385">color_parts(rgba(R, G, B, A), R, G, B, A).</font></div><div><font face="APL385">color_parts(c(C), R, G, B, A) :- color_rgba(C, R, G, B, A).</font></div><div><br></div><div><br></div><div>The preceding proredicate is supported by color_rgba/5:</div><div><br></div><div><font face="APL385">:- pred color_rgba(p_color::in, uint8::out, uint8::out, uint8::out,</font></div><div><font face="APL385">    uint8::out) is det.</font></div><div><font face="APL385"><br></font></div><div><font face="APL385">color_rgba(lightgray , 200u8, 200u8, 200u8, 255u8).</font></div><div><font face="APL385">color_rgba(gray      , 130u8, 130u8, 130u8, 255u8).</font></div><div><font face="APL385">color_rgba(darkgray  , 80u8, 80u8, 80u8, 255u8).</font></div><div><font face="APL385">:</font></div><div><br></div><div><br></div><div>My question then is: Is there a more compact, clean and probably more</div><div>efficient way to handle the passing by value so that I don't have to keep</div><div>breaking something into 4 uint8s, only to then have to recompose them inside</div><div>the C handler?</div><div><br></div><div>That to me seems totally inefficient and somewhat silly at this moment in</div><div>time.</div><div><br></div><div>I am currently experimenting with passing a uint32 and casting it as a</div><div>Color but I am always very interested to see others suggestions!</div><div><br></div><div>Thank you,</div><div>Sean.</div><div><br></div></body></html>