1

BooBoo Updates Thread
Posted by tremblin on 2024-12-05, 11:21pm
Avatar
A new first parameter has been added to joystick events - the joystick index (0=1st, 1=2nd joystick, ...)

This is released as 2.2.14.
Replies (24)
Posted by tremblin on 2024-12-10, 6:11pm
Avatar
Updated the demos downloads to the latest version of BooBoo/scripts.
Posted by tremblin on 2024-12-10, 8:39pm
Avatar
Only difference from before is everything between 2.1 and 2.2.14 which was pretty much 2-3 small things each revision mostly. The games didn't change. But a few API they use changed slightly and was corrected in the games and launcher.
Posted by tremblin on 2024-12-11, 8:59pm
Avatar
https://cmykilluminati.net/media/stuff/gui_transitions.mp4

You can now customize the GUI transitions (git) and I added an example to tinker with it, shown above.
Posted by tremblin on 2024-12-11, 9:43pm
Avatar
I removed all the "fit" widgets stuff, as it's always confusing.
Posted by tremblin on 2024-12-12, 2:25am
Avatar
EDIT: this is the updated code from 2.2.15 which supports keyboard/joystick input

number exited
= exited FALSE

vector groups
vector_add groups 0
vector_add groups 1

number font
font_load font "vga.ttf" 12 1

map c c_both c_left c_right ll lr l1 l2 l3 l4 l5 r1 r2 r3 r4 r5 bcycle ; widget userdata
number wc wc_both wc_left wc_right wll wlr wl1 wl2 wl3 wl4 wl5 wr1 wr2 wr3 wr4 wr5 wbcycle ; widgets

function start_gui
{
        map_set c "draw" draw_window
        map_set c "event" null_event
        map_set c_both "draw" draw_nothing
        map_set c_both "event" null_event
        map_set c_left "draw" draw_nothing
        map_set c_left "event" null_event
        map_set c_right "draw" draw_nothing
        map_set c_right "event" null_event
        call_result ll mklabel "IN"
        call_result lr mklabel "OUT"
        pointer g1 g2
        address g1 [groups 0]
        address g2 [groups 1]
        call_result l1 mkradio g1 0 "Enlarge"
        call_result l2 mkradio g1 1 "Shrink"
        call_result l3 mkradio g1 2 "Appear"
        call_result l4 mkradio g1 3 "Slide"
        call_result l5 mkradio g1 4 "V. Slide"
        call_result r1 mkradio g2 0 "Enlarge"
        call_result r2 mkradio g2 1 "Shrink"
        call_result r3 mkradio g2 2 "Appear"
        call_result r4 mkradio g2 3 "Slide"
        call_result r5 mkradio g2 4 "V. Slide"
        call_result bcycle mkbutton "Cycle GUI" cycle_gui

        widget_create wll 1 30 ll
        widget_set_accepts_focus wll FALSE
        widget_create wl1 200 30 l1
        widget_create wl2 200 30 l2
        widget_create wl3 200 30 l3
        widget_create wl4 200 30 l4
        widget_create wl5 200 30 l5
        widget_create wc_left 200 100 c_left
        widget_set_accepts_focus wc_left FALSE
        widget_set_parent wll wc_left
        widget_set_parent wl1 wc_left
        widget_set_parent wl2 wc_left
        widget_set_parent wl3 wc_left
        widget_set_parent wl4 wc_left
        widget_set_parent wl5 wc_left

        widget_create wlr 1 30 lr
        widget_set_accepts_focus wlr FALSE
        widget_create wr1 200 30 r1
        widget_create wr2 200 30 r2
        widget_create wr3 200 30 r3
        widget_create wr4 200 30 r4
        widget_create wr5 200 30 r5
        widget_create wc_right 200 150 c_right
        widget_set_accepts_focus wc_right FALSE
        widget_set_parent wlr wc_right
        widget_set_parent wr1 wc_right
        widget_set_parent wr2 wc_right
        widget_set_parent wr3 wc_right
        widget_set_parent wr4 wc_right
        widget_set_parent wr5 wc_right

        widget_create wc_both 400 180 c_both
        widget_set_accepts_focus wc_both FALSE
        widget_set_parent wc_left wc_both
        widget_set_parent wc_right wc_both

        widget_create wc 400 210 c
        widget_set_accepts_focus wc FALSE
        widget_set_parent wc_both wc
        widget_create wbcycle 400 30 bcycle
        widget_set_break_line wbcycle TRUE
        widget_set_parent wbcycle wc

        gui_start wc
}

call start_gui

gui_set_focus wl1

function draw_nothing x y w h focussed data
{
}

function draw_window x y w h focussed data
{
        filled_rectangle 0 0 255 255 0 0 255 255 0 0 255 255 0 0 255 255 x y w h
}

function draw_button x y w h focussed data
{
        number r g b
        if (== focussed TRUE) yellow white
                = r 255
                = g 255
                = b 0
        :yellow
                = r 255
                = g 255
                = b 255
        :white
        number tw th
        font_width font tw [data "text"]
        font_height font th

        number xx yy
        = xx (+ x (/ w 2))
        - xx (/ tw 2)
        = yy (+ y (/ h 2))
        - yy (/ th 2)

        number ox oy
        if (== [data "down"] TRUE) offset no_offset
                = ox 5
                = oy 5
        :offset
                = ox 0
                = oy 0
        :no_offset

        + x ox
        + y oy
        + xx ox
        + yy oy

        filled_rectangle 0 0 255 255 0 0 255 255 0 255 255 255 0 255 255 255 x y w h
        rectangle r g b 255 x y w h 2
        font_draw font r g b 255 [data "text"] xx yy
}

function draw_label x y w h focussed data
{
        number tw th
        font_width font tw [data "text"]
        font_height font th

        number xx yy
        = xx (+ x (/ w 2))
        - xx (/ tw 2)
        = yy (+ y (/ h 2))
        - yy (/ th 2)

        filled_rectangle 0 0 255 255 0 0 255 255 0 255 255 255 0 255 255 255 x y w h
        font_draw font 255 255 255 255 [data "text"] xx yy
}

function draw_radio x y w h focussed data
{
        number tw th cy
        font_width font tw [data "text"]
        font_height font th

        number xx yy
        = xx (+ x 20)
        = yy (+ y (/ h 2))
        = cy yy
        - yy (/ th 2)

        filled_rectangle 0 0 255 255 0 0 255 255 0 0 255 255 0 0 255 255 x y w h
        font_draw font 255 255 255 255 [data "text"] (+ xx 20) yy

        circle 255 255 255 255 (+ xx 10) cy 7 1 -1

        if (== `[data "group"] [data "index"]) check
                filled_circle 255 255 255 255 (+ xx 10) cy 5 -1
        :check
        
        if (== focussed 1) draw_focus
                rectangle 255 255 0 255 x y w h 2
        :draw_focus
}

function null_event type a b c d x y w h focussed ~data
{
}

function button_event type a b c d x y w h focussed ~data
{
        if (&& (== type EVENT_MOUSE_DOWN) (== a 1) (== b FALSE)) down
                number on_button
                call_result on_button owned x y w h c d
                if (== on_button TRUE) really_down
                        map_set data "down" TRUE
                :really_down
        :down

        if (&& (== [data "down"] TRUE) (== type EVENT_MOUSE_UP)) up
                number on_button
                call_result on_button owned x y w h c d
                if (== on_button TRUE) really_up
                        call [data "callback"]
                :really_up
                map_set data "down" FALSE
        :up

        if (&& (== TRUE focussed) (== FALSE b) (|| (&& (== type EVENT_KEY_DOWN) (== KEY_RETURN a)) (&& (== type EVENT_JOY_DOWN) (== b JOY_A)))) down2
                map_set data "down" TRUE
        :down2
        if (&& (== [data "down"] TRUE) (== TRUE focussed) (|| (&& (== type EVENT_KEY_UP) (== KEY_RETURN a)) (&& (== type EVENT_JOY_UP) (== b JOY_A)))) play_it
                call [data "callback"]
                map_set data "down" FALSE
        :play_it
}

function radio_event type a b c d x y w h focussed ~data
{
        if (&& (== type EVENT_MOUSE_DOWN) (== a 1) (== b FALSE)) down
                number on_button
                call_result on_button owned x y w h c d
                if (== on_button TRUE) really_down
                        = `[data "group"] [data "index"]
                :really_down
        :down
        if (&& (== TRUE focussed) (== FALSE b) (|| (&& (== type EVENT_KEY_DOWN) (== KEY_RETURN a)) (&& (== type EVENT_JOY_DOWN) (== b JOY_A)))) down2
                = `[data "group"] [data "index"]
        :down2
}

function mkbutton text callback
{
        map m
        map_set m "text" text
        map_set m "draw" draw_button
        map_set m "event" button_event
        map_set m "callback" callback
        map_set m "down" FALSE
        return m
}

function mklabel text
{
        map m
        map_set m "text" text
        map_set m "draw" draw_label
        map_set m "event" null_event
        return m
}

function mkradio group index text
{
        map m
        map_set m "text" text
        map_set m "draw" draw_radio
        map_set m "event" radio_event
        map_set m "group" group
        map_set m "index" index
        return m
}

function owned wx wy ww wh x y
{
        if (|| (< x wx) (< y wy) (>= x (+ wx ww)) (>= y (+ wy wh))) nope
                return FALSE
        :nope
        return TRUE
}

function gui_event id type a b c d x y w h focussed ~data
{
        call [data "event"] type a b c d x y w h focussed data
}

function gui_draw id x y w h focussed data
{
        call [data "draw"] x y w h focussed data
}

function cycle_gui
{
        gui_set_transition_types [groups 0] [groups 1]
        gui_exit
        = exited TRUE
}

function event type a b c d
{
        if (== exited FALSE) no
                return
        :no
        if (&& (== type EVENT_KEY_DOWN) (== a KEY_SPACE)) again
                = exited FALSE
                call start_gui
        :again
}

function draw
{
        if (== exited FALSE) back
                return
        :back

        font_draw font 255 255 255 255 "Press SPACE to restart GUI" 10 10
}


This is the code for the video 2 posts above...

You can see the limitation of no pointers. The groups global could be put as a pointer into wl1..wl5 etc but instead it has to be a global. I also made an example for myself with a checkbox, and it could be improved with pointers too. But it's a question of simplicity vs. adding pointers, I had a pointer type at one point but it worked kinda weird... I've thought about it and I could add them back with a dereference operator but it adds a lot of complexity both to learning BooBoo (which can be educational) and it bloats the code. I think there's tonnes of games that could be made as it is so I'm not leaning toward adding pointers but who knows.

The api for pointers I had in mind was something like

pointer p ; define a pointer
address p some_var ; take the address of some_var
; now assigning to p without a dereference is undefined
= p some_num ; undefined
; but you could assign to the value pointed to by p (some_var) with a dereference
= ^p some_num
; Assigning to pointer itself can only be done on untyped destinations:
= some_num p ; undefined or error
= [v 0] p ; [v 0] now points to some_var
; Now if you were to do:
= [v 0] 10
; ^ That replaces the pointer with a number, but
= ^[v 0] 10
; some 'some_var' to 10
Posted by tremblin on 2024-12-12, 4:18am
Avatar
A few things could be done with that example like kb/joystick control of radio buttons, which'll probably just look like the focus has been lost and won't respond to input until a focus rectangle is drawn in draw_radio and kb/joystick events are handled in radio_event.

EDIT: This was done for 2.2.15
Posted by tremblin on 2024-12-12, 6:42am
Avatar
number n
= n 10
pointer p
address p n
= !p 20
print "%\n" n
print "%\n" !p

map m
= [m "foo"] p
= ![m "foo"] 30
print "%\n" n
= [m "foo"] 40
print "%\n" [m "foo"]

address p [m "foo"]
= !p 50
print "%\n" [m "foo"]


This pointers example is working in git. It prints:


20
20
30
40
50
Posted by tremblin on 2024-12-12, 6:46am
Avatar
Might still be some corner cases missing for pointer support, but basically all there.
Posted by tremblin on 2024-12-12, 9:15am
Avatar
2.2.15 is released:
  • Change Nooskewl example to the canonical animation
  • Don't add game engine constants to CLI build namespace
  • Configurable GUI transitions with example
  • Remove FIT_X/FIT_Y stuff from GUI API
  • Add pointer type with CLI example
Posted by tremblin on 2024-12-12, 9:20am
Avatar
The dereference operator is a backtick (`), the documentation online is updated.
Posted by tremblin on 2024-12-12, 10:03am
Avatar
Pointers work with functions too... actually you could always use function pointers stuff into typeless variables, now you can do it two ways:

function foo
{
        print "FOO\n"
}

pointer p
address p foo
call `p

call bar foo

function bar bazoo
{
        call bazoo
}


Prints FOO twice.

The second "call bar foo" was always supported, as well you can directly store functions into vectors/maps:

map m
= [m "callback"] foo
call [m "callback"] ; print FOO


Whereas if you're using pointers...

pointer p
address p foo
map m
= [m "callback"] p
call `[m "callback"] ; call [m "callback"] will probably crash or (should eventually, once everything is buttoned up) throw an error


Functions are just a type of variable like number, map etc except there isn't a way to define a variable of that type other than declaring a function. Same with labels. You can pass labels into a vector if you wanted although I think it's useless, you can also pass them into functions, since labels inside functions are out of scope, and you can't jump out of a function, it's also useless, but I can see using them in pointers to maybe have some use:

pointer p
address p bar
goto `p

:foo
print "FOO\n"
goto done
:bar
print "BAR\n"
goto done
:baz
print "BAZ\n"
goto done

:done


This prints BAR
Posted by tremblin on 2024-12-12, 10:46am
Avatar
(due to not much use without it, labels and functions can be seen if they're declared after that point, as the compiler has 2 passes)
Posted by tremblin on 2024-12-13, 8:23pm
Avatar
I added Fade and None to GUI transitions... they all work without resizing the window, due to the automatic placement of "black bars" I still need to fix some of the transitions when the window is resized.
Posted by tremblin on 2024-12-13, 9:33pm
Avatar

vector_reserve
fade, none gui transitions
fix transitions for black bars
custom black bars - set projection, pass a user function
target (left/right/top/bottom) x, y, w, h


This is my todo list.
Posted by tremblin on 2024-12-13, 9:51pm
Avatar
The only time you, as a user, has to deal with "black bar" crap is with shaders while targetting the backbuffer. You should be able to avoid it altogether with shaders, by using a render target the size of your buffer. It's only an issue with some types of shaders, like if you are using gl_FragCoord. You would expect the renderable area to have a 0->1 gl_FragCoord however the black bars account for some of that space. You can work around it in your shaders, using the BooBoo functions to get the offset of the black bars and passing them into shaders.
Posted by tremblin on 2024-12-14, 8:51am
Avatar
I fixed all the GUI transitions including the new fade. I removed appear. It's not really a general purpose transition and was only there for Dog-O which uses it for its menus. It also requires a shader so the D3D port requires one fewer external shader now.

When the window is "tall" now the drawing area is centred instead of offset to the top. The intention of offset it upwards is to allow touch controls, but I don't intend to work on Android/Apple again.
Posted by tremblin on 2024-12-14, 9:45pm
Avatar
https://cmykilluminati.net/media/stuff/blackbars.mp4

It now supports custom "black bars" in git.
Posted by tremblin on 2024-12-14, 9:49pm
Avatar
Here's the code for it, but this example doesn't include the moving triangle, for simplicity of demonstration:

number iv ih it
image_load iv "vert.png"
image_load ih "horiz.png"
image_load it "tile.png"

number v_w v_h h_w h_h t_w t_h
image_size iv v_w v_h
image_size ih h_w h_h
image_size it t_w t_h

function draw_black_bar type x y w h
{
        number scale
        = scale 3

        number scr_w scr_h
        get_screen_size scr_w scr_h
        
        number xx yy

        if (== type BAR_TOP) top (== type BAR_BOTTOM) bottom (== type BAR_LEFT) left right
                = xx w
                / xx (* h_w scale)
                floor xx
                + xx 1
                * xx (* h_w scale)
                - xx w
                / xx 2
                neg xx
                = yy (- (+ y h) (* h_h scale))
                call htile ih xx yy w h scale
                = xx w
                / xx (* t_w scale)
                floor xx
                + xx 1
                * xx (* t_w scale)
                - xx w
                / xx 2
                neg xx
                if (> yy 0) tile
                        :again
                        - yy (* t_h scale)
                        call htile it xx yy w h scale
                        ? yy 0
                        jg again
                :tile
        :top
                = xx w
                / xx (* h_w scale)
                floor xx
                + xx 1
                * xx (* h_w scale)
                - xx w
                / xx 2
                neg xx
                = yy y
                call htile ih xx yy w h scale
                = xx w
                / xx (* t_w scale)
                floor xx
                + xx 1
                * xx (* t_w scale)
                - xx w
                / xx 2
                neg xx
                + yy (* h_h scale)
                if (< yy scr_h) tile2
                        :again2
                        call htile it xx yy w h scale
                        + yy (* t_h scale)
                        ? yy scr_h
                        jl again2
                :tile2
        :bottom
                = yy h
                / yy (* v_h scale)
                floor yy
                + yy 1
                * yy (* v_h scale)
                - yy h
                / yy 2
                neg yy
                = xx (- (+ x w) (* v_w scale))
                call vtile iv xx yy w h scale
                = yy h
                / yy (* t_h scale)
                floor yy
                + yy 1
                * yy (* t_h scale)
                - yy h
                / yy 2
                neg yy
                if (> xx 0) tile3
                        :again3
                        - xx (* t_w scale)
                        call vtile it xx yy w h scale
                        ? xx 0
                        jg again3
                :tile3
        :left
                = yy h
                / yy (* v_h scale)
                floor yy
                + yy 1
                * yy (* v_h scale)
                - yy h
                / yy 2
                neg yy
                = xx x
                call vtile iv xx yy w h scale
                = yy h
                / yy (* t_h scale)
                floor yy
                + yy 1
                * yy (* t_h scale)
                - yy h
                / yy 2
                neg yy
                + xx (* v_w scale)
                if (< xx scr_w) tile4
                        :again4
                        call vtile it xx yy w h scale
                        + xx (* t_w scale)
                        ? xx scr_w
                        jl again4
                :tile4
        :right        
}

function htile img x y w h scale
{
        number img_w img_h
        image_size img img_w img_h

:top
        image_stretch_region img 255 255 255 255 0 0 img_w img_h x y (* img_w scale) (* img_h scale) 0 0
        + x (* img_w scale)
        ? x w
        jl top
}

function vtile img x y w h scale
{
        number img_w img_h
        image_size img img_w img_h

:top
        image_stretch_region img 255 255 255 255 0 0 img_w img_h x y (* img_w scale) (* img_h scale) 0 0
        + y (* img_h scale)
        ? y h
        jl top
}


draw_black_bar gets called 0 or 2 times depending what needs to be drawn, every time the screen is cleared which happens automatically after draw is called.
Posted by tremblin on 2024-12-14, 11:26pm
Avatar
https://cmykilluminati.net/media/stuff/blackbarslinux.mp4

It resizes a lot smoother on Linux.
Posted by tremblin on 2024-12-14, 11:34pm
Avatar
2.2.16 is uploaded with these changes since 2.2.15:
  • Added function and label pointers CLI examples
  • Remove "Appear" gui transition, add None and Fade
  • Support for drawing your own custom "black bars" for wide/tall aspect ratios
  • Fixes
Posted by tremblin on 2024-12-15, 4:25am
Avatar
In that example, It looks like about half the code is to get the tiling centred rather than starting at the top left with a full tile and ending up with probably half a tile on the bottom. Roughly half the lines of code are for that reason.

                = xx w
                / xx (* h_w scale)
                floor xx
                + xx 1
                * xx (* h_w scale)
                - xx w
                / xx 2
                neg xx


All that which is repeated slightly differently 8 times is to get the thing centred.

You could also write it like:

                = xx (/ w (* h_w scale))
                floor xx
                = xx (/ (- (* (+ xx 1) (* h_w scale)) w) 2)
                neg xx
Posted by tremblin on 2024-12-15, 4:35am
Avatar
or just * -1 instead of neg. Then it's 3 lines.
Posted by tremblin on 2024-12-16, 12:02am
Avatar
https://cmykilluminati.net/media/stuff/blackbarsdefault.mp4

There is now a gradient drawn by default instead of black bars, you can still override it.

My microphone is blaring on Linux.
Posted by tremblin on 2024-12-18, 4:01am
Avatar
I've enabled multisampling in git. 4 samples. 16 samples doesn't work on my RX 6400 so likely wouldn't be widely supported, 8 might, but 4 looks good anyway and should be widely supported.



Here's a multisampled thick triangle.
1

Post a Reply

Please log in to reply.

© 2024 CMYKilluminatiNetwork