[m-users.] Calling pass-by-value with C FFI with raylib
Sean Charles (emacstheviking)
objitsu at gmail.com
Sat Jul 15 18:08:11 AEST 2023
Thanks all, Zoltan and Peter on point as usual.
I had a good long think about what I am doing, writing an IDE as there are not enough editors in the world already, one that is customised to the transpiler I have written, also written in Mercury, in fact the two may well become a single application but for now the remain separated. I can't decide wether to implement LSP in the transpiler as a command line option, making my editor more generic, or to use zeromq and just make them talk sooner. First world problem.
Anyway, I realised that, writing an editor, I am far more concerned with having all of the wonderful advantages that the Mercury compiler gives me rather than worry about performance over bit fiddling some colour values, thus I opted to do any bit shifting etc at the point of creation of my ui objects and then just as Peter recommended, pass a uint32 across the FFI boundary. So far this is working absolutely fine, so thank you all again for your guiding input.
The code I have ended up with so far is (so far) structured like this.
For the creation of new entities that can on-screen:
new_cursor(X, Y, Color) = cursor(X, Y, to_rgba(Color)).
new_text(Str, X, Y, Size, Color) =
text(Str, X, Y, Size, to_rgba(Color)).
:- func to_rgba(color::in) = (uint32::out) is det.
to_rgba(C) = RGBA :-
color_parts(C, R, G, B, A),
RGBA = uint32.from_bytes_le(R, G, B, A).
These are then rendered on a case by case basis, I will add more state to them as the need arise, the raylib library has tweening functions for example, so I intend to make things be able to fade in, out, move about etc as you interact with the code. That's the vision!
% Drawing the graphics objects.
% Cursor
ui_draw(cursor(X, Y, C), !IO) :-
draw_rectangle(X, Y, 10, 20, C, !IO).
ui_draw(text(Str, X, Y, Size, C), !IO) :-
draw_text(Str, X, Y, Size, C, !IO).
And my very simple UI main loop just checks to see if it show/not show the cursor, I will move that functionality into the UI objects I think, giving a reference to the current world state so each object can make it's own decisions on how to render, or not. As I say it is early days.
:- type world
---> world(
wFrameTime ::float,
wTime ::float,
f1Hz ::bool
).
:- pred run_loop(world::in, world::out, io::di, io::uo) is det.
run_loop(!W, !IO) :-
window_should_close(X, !IO),
(
X = yes,
trace_log("Stopped by user", [], !IO)
;
X = no,
% Update world state.
get_frame_time(FT, !IO),
get_time(T, !IO),
!:W = !.W ^wFrameTime := FT,
!:W = !.W ^wTime := T,
% 1Hz timer flag
Hz1 = float.round_to_int(wTime(!.W)) mod 2,
(if Hz1 = 1 then Hz1On = yes else Hz1On = no),
!:W = !.W ^f1Hz := Hz1On,
begin_drawing(!IO),
clear_background(color(raywhite), !IO),
draw_fps(0, 0, !IO),
( if f1Hz(!.W) = yes then
ui_draw(new_cursor(140, 100, color(purple)), !IO)
else
true
),
ui_draw(new_text(
string.format("frameTime: %f", [ f(wFrameTime(!.W))]),
120, 130, 20, color(red)), !IO),
ui_draw(new_text(
string.format("time: %f", [ f(wTime(!.W))]),
120, 150, 20, color(blue)), !IO),
end_drawing(!IO),
% File dropping
dropped_files(Files, !IO),
( if list.is_not_empty(Files) then
io.write_list(Files, "\n", io.print_line, !IO)
else
true
),
run_loop(!W, !IO)
).
My influences for the project are the Squeak Morphic system (its inheritence and approach, I was a big Squeak addict once) and of course 'that demo' by Douglas Englebart in the DARPA video.
I have no idea where this is taking me but it sure is a pleasant journey and a whole lot of fun! Mercury just makes me know that the code I write is going to be robust and well thought out, I live in fear of dangling references with C/assembler which is why my C FFI code checks every single things passed to it and only calls the C function if it is satisfied with its inputs!
Thanks,
Sean.
> On 14 Jul 2023, at 08:51, Peter Wang <novalazy at gmail.com> wrote:
>
> On Fri, 14 Jul 2023 07:29:10 +0100 "Sean Charles (emacstheviking)" <objitsu at gmail.com> wrote:
>>
>> The only real way I could find to model that in Mercury has been to literally
>> re-invent the weel and create this union type and then some helpers:
>>
>> :- type p_color
>> ---> lightgray
>> ; gray
>> ; yellow
>> :
>> ; raywhite. % FInal colour from header file palette
>>
>> :- type color
>> ---> rgb(uint8, uint8, uint8)
>> ; rgba(uint8, uint8, uint8, uint8)
>> ; c(p_color).
>
> I expect you don't actually need color to be a Mercury d.u. type,
> so you can define color as a uint32, and have predicates/functions
> that convert between colors and color components.
>
> Peter
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.mercurylang.org/archives/users/attachments/20230715/705d9042/attachment.html>
More information about the users
mailing list