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