1DOLLY 72PACKAGE raylib3REQUIRES HOST runtime@04REQUIRES HOST display@05REQUIRES HOST input@06REQUIRES HOST touch@078# raylib 6.0 from upstream's source, unchanged, with its software renderer and9# Dolly's platform backend (rcore_dolly.c, compiled into raylib's rcore.c as10# its custom platform): InitWindow shows the frames through display@0, keys,11# text, the pointer and the wheel come from input@0, fingers from touch@0, and12# GetTime reads the monotonic clock. <dolly/raylib.h> serves a program that holds the display13# itself. For programs the cc package builds.14FROM /v0.1.4/Dollyfile-system 915c71d4ce772989e3076060967824e48ccd6a1a6259624fe6213542df088dbc15INSTALL /v0.1.4/Dollyfile-libdolly-touch 07fbd180b1e76facefc348682df905541fb536cfe01cb1b871e8b6d7e884cba516REQUIRES HEADER libc17REQUIRES HEADER display18REQUIRES HEADER input19REQUIRES HEADER touch20REQUIRES TOOL   ar21REQUIRES TOOL   cc22REQUIRES TOOL   make23REQUIRES TOOL   mkdir24REQUIRES TOOL   rm25REQUIRES TOOL   tar2627SOURCE /v0.1.4/dist/static/gamedev/raylib.tar b16dd083b9205e14f8b79a1d91c934b579c9a92bcb4e3af0e374f3e71dcf82d3 /tmp/raylib.tar28FILE /usr/src/dolly/raylib/raylib.mk29    CC := cc30    AR := ar31    SOURCE := /usr/src/raylib/src32    BUILD := /usr/src/dolly/raylib/build33    FLAGS := -std=gnu99 -O2 -D_GNU_SOURCE -DGRAPHICS_API_OPENGL_SOFTWARE -DSW_FRAMEBUFFER_OUTPUT_BGRA=0 -fno-strict-aliasing -fno-builtin -I $(SOURCE)34    OBJECTS := $(patsubst %,$(BUILD)/%.o,rcore rshapes rtextures rtext rmodels)35    36    .PHONY: all37    38    all: /usr/lib/libraylib.a /usr/lib/libdolly-raylib.a39    40    $(BUILD)/%.o: $(SOURCE)/%.c41    	mkdir -p $(BUILD)42    	$(CC) $(FLAGS) -c $< -o $@43    44    # rtext.c triggers the embedded LLVM backend's current high-optimization45    # memory/trap limit. Text layout is not the software 3D render hot path, so46    # keep this one upstream translation unit at the reliable bootstrap level.47    $(BUILD)/rtext.o: $(SOURCE)/rtext.c48    	mkdir -p $(BUILD)49    	$(CC) $(subst -O2,-O0,$(FLAGS)) -c $< -o $@50    51    # raylib's core with Dolly's platform backend in the same unit.52    $(BUILD)/rcore.o: /usr/src/dolly/raylib/rcore-dolly.c /usr/src/dolly/raylib/rcore_dolly.c $(SOURCE)/rcore.c53    	mkdir -p $(BUILD)54    	$(CC) $(FLAGS) -I /usr/src/dolly/raylib -c $< -o $@55    56    /usr/lib/libraylib.a: $(OBJECTS)57    	$(AR) rcs $@ $(OBJECTS)58    	cp $(SOURCE)/raylib.h $(SOURCE)/raymath.h $(SOURCE)/rlgl.h /usr/include/59    60    /usr/lib/libdolly-raylib.a: /usr/src/dolly/raylib/dolly-raylib.c /usr/src/dolly/raylib/dolly-raylib.h /usr/lib/libraylib.a61    	mkdir -p /usr/include/dolly62    	cp /usr/src/dolly/raylib/dolly-raylib.h /usr/include/dolly/raylib.h63    	$(CC) -std=c17 -O2 -fno-builtin -I /usr/src/dolly/raylib -c /usr/src/dolly/raylib/dolly-raylib.c -o $(BUILD)/dolly-raylib.o64    	$(AR) rcs $@ $(BUILD)/dolly-raylib.o65FILE /usr/src/dolly/raylib/rcore-dolly.c66    // raylib's core with Dolly's platform backend: built with no PLATFORM_* defined,67    // rcore.c includes no backend of its own, and Dolly's follows it in this unit.68    #include "rcore.c"69    #include "rcore_dolly.c"70FILE /usr/src/dolly/raylib/rcore_dolly.c71    // raylib's platform backend for Dolly, built into raylib's own rcore.c as its72    // custom platform (rcore-dolly.c includes rcore.c, then this file):73    //   - the window is display@0's surface, sized as InitWindow asks; a frame is74    //     presented in SwapScreenBuffer and paced by the page's animation frames;75    //   - keys, text, the pointer and the wheel come from input@0 in PollInputEvents;76    //   - fingers come from touch@0 where the page has a touchscreen for the program;77    //   - the clock is CLOCK_MONOTONIC.78    // A hidden window (FLAG_WINDOW_HIDDEN), or a program that already holds the79    // display (it composes raylib's frame into its own, or opened it through80    // <dolly/raylib.h>), has raylib render to memory only: the program presents81    // the frame and hands raylib its key events through DollyRaylibInputEvent.82    #include <dolly/display.h>83    #include <dolly/input.h>84    #include <dolly/touch.h>85    #include <time.h>86    87    typedef struct {88        int window;                         // raylib holds the display and the input89        dolly_display_surface surface;90        uint64_t input;91        uint64_t touch;                     // 0 without fingers92        uint32_t animationFrame;93        double start;94    } PlatformData;95    96    static PlatformData platform = { 0 };97    98    // A key or button pressed and released between two frames still reads as99    // pressed for one frame: its release waits for the next PollInputEvents.100    static char keyReleaseNext[MAX_KEYBOARD_KEYS] = { 0 };101    static char buttonReleaseNext[MAX_MOUSE_BUTTONS] = { 0 };102    static char touchReleaseNext = 0;103    104    static double MonotonicSeconds(void)105    {106        struct timespec now = { 0 };107        clock_gettime(CLOCK_MONOTONIC, &now);108        return (double)now.tv_sec + (double)now.tv_nsec*1e-9;109    }110    111    // KeyboardEvent.code of a key record, as raylib's KeyboardKey.112    static int KeyFromCode(const char *code, int length)113    {114        static const struct { const char *code; int key; } keys[] = {115            { "Space", KEY_SPACE }, { "Quote", KEY_APOSTROPHE }, { "Comma", KEY_COMMA }, { "Minus", KEY_MINUS },116            { "Period", KEY_PERIOD }, { "Slash", KEY_SLASH }, { "Semicolon", KEY_SEMICOLON }, { "Equal", KEY_EQUAL },117            { "BracketLeft", KEY_LEFT_BRACKET }, { "Backslash", KEY_BACKSLASH }, { "BracketRight", KEY_RIGHT_BRACKET },118            { "Backquote", KEY_GRAVE }, { "Escape", KEY_ESCAPE }, { "Enter", KEY_ENTER }, { "Tab", KEY_TAB },119            { "Backspace", KEY_BACKSPACE }, { "Insert", KEY_INSERT }, { "Delete", KEY_DELETE },120            { "ArrowRight", KEY_RIGHT }, { "ArrowLeft", KEY_LEFT }, { "ArrowDown", KEY_DOWN }, { "ArrowUp", KEY_UP },121            { "PageUp", KEY_PAGE_UP }, { "PageDown", KEY_PAGE_DOWN }, { "Home", KEY_HOME }, { "End", KEY_END },122            { "CapsLock", KEY_CAPS_LOCK }, { "ScrollLock", KEY_SCROLL_LOCK }, { "NumLock", KEY_NUM_LOCK },123            { "PrintScreen", KEY_PRINT_SCREEN }, { "Pause", KEY_PAUSE },124            { "ShiftLeft", KEY_LEFT_SHIFT }, { "ControlLeft", KEY_LEFT_CONTROL }, { "AltLeft", KEY_LEFT_ALT },125            { "MetaLeft", KEY_LEFT_SUPER }, { "ShiftRight", KEY_RIGHT_SHIFT }, { "ControlRight", KEY_RIGHT_CONTROL },126            { "AltRight", KEY_RIGHT_ALT }, { "MetaRight", KEY_RIGHT_SUPER }, { "ContextMenu", KEY_KB_MENU },127            { "NumpadDecimal", KEY_KP_DECIMAL }, { "NumpadDivide", KEY_KP_DIVIDE }, { "NumpadMultiply", KEY_KP_MULTIPLY },128            { "NumpadSubtract", KEY_KP_SUBTRACT }, { "NumpadAdd", KEY_KP_ADD }, { "NumpadEnter", KEY_KP_ENTER },129            { "NumpadEqual", KEY_KP_EQUAL },130        };131        if ((length == 4) && (strncmp(code, "Key", 3) == 0) && (code[3] >= 'A') && (code[3] <= 'Z')) return KEY_A + (code[3] - 'A');132        if ((length == 6) && (strncmp(code, "Digit", 5) == 0) && (code[5] >= '0') && (code[5] <= '9')) return KEY_ZERO + (code[5] - '0');133        if ((length == 7) && (strncmp(code, "Numpad", 6) == 0) && (code[6] >= '0') && (code[6] <= '9')) return KEY_KP_0 + (code[6] - '0');134        if ((length >= 2) && (length <= 3) && (code[0] == 'F'))135        {136            int number = atoi(code + 1);137            if ((number >= 1) && (number <= 12)) return KEY_F1 + number - 1;138        }139        for (size_t i = 0; i < sizeof(keys)/sizeof(keys[0]); i++)140        {141            if (((int)strlen(keys[i].code) == length) && (strncmp(keys[i].code, code, length) == 0)) return keys[i].key;142        }143        return KEY_NULL;144    }145    146    static void QueueCharacter(int codepoint)147    {148        if (CORE.Input.Keyboard.charPressedQueueCount < MAX_CHAR_PRESSED_QUEUE)149        {150            CORE.Input.Keyboard.charPressedQueue[CORE.Input.Keyboard.charPressedQueueCount] = codepoint;151            CORE.Input.Keyboard.charPressedQueueCount++;152        }153    }154    155    // One input@0 record into raylib's keyboard, character and mouse state.156    void DollyRaylibInputEvent(const dolly_input_event *event)157    {158        if (event->type == DOLLY_INPUT_EVENT_KEY)159        {160            int key = KeyFromCode((const char *)event->data + event->key_length, event->code_length);161            if ((key <= KEY_NULL) || (key >= MAX_KEYBOARD_KEYS)) return;162            if (event->action == DOLLY_KEY_ACTION_RELEASE)163            {164                if (CORE.Input.Keyboard.previousKeyState[key] == 0) keyReleaseNext[key] = 1;165                else CORE.Input.Keyboard.currentKeyState[key] = 0;166            }167            else168            {169                if (event->action == DOLLY_KEY_ACTION_REPEAT) CORE.Input.Keyboard.keyRepeatInFrame[key] = 1;170                else171                {172                    CORE.Input.Keyboard.currentKeyState[key] = 1;173                    if (CORE.Input.Keyboard.keyPressedQueueCount < MAX_KEY_PRESSED_QUEUE)174                    {175                        CORE.Input.Keyboard.keyPressedQueue[CORE.Input.Keyboard.keyPressedQueueCount] = key;176                        CORE.Input.Keyboard.keyPressedQueueCount++;177                    }178                }179                if (key == CORE.Input.Keyboard.exitKey) CORE.Window.shouldClose = true;180            }181        }182        else if (event->type == DOLLY_INPUT_EVENT_TEXT)183        {184            const unsigned char *text = event->data + event->key_length + event->code_length;185            for (int offset = 0; offset < event->text_length;)186            {187                int size = 0;188                int codepoint = GetCodepointNext((const char *)text + offset, &size);189                if (size <= 0) break;190                QueueCharacter(codepoint);191                offset += size;192            }193        }194        else if (event->type == DOLLY_INPUT_EVENT_POINTER)195        {196            // A browser numbers left, middle, right, back, forward; raylib left, right, middle, side, extra, forward, back.197            static const int buttons[] = { MOUSE_BUTTON_LEFT, MOUSE_BUTTON_MIDDLE, MOUSE_BUTTON_RIGHT, MOUSE_BUTTON_BACK, MOUSE_BUTTON_FORWARD };198            unsigned int button = event->flags >> 8;199            CORE.Input.Mouse.currentPosition = (Vector2){ (float)event->x, (float)event->y };200            CORE.Input.Touch.position[0] = CORE.Input.Mouse.currentPosition;201            if ((button < 5) && (event->action != DOLLY_POINTER_ACTION_DRAG))202            {203                int mouse = buttons[button];204                if (event->action == DOLLY_POINTER_ACTION_PRESS) CORE.Input.Mouse.currentButtonState[mouse] = 1;205                else if (CORE.Input.Mouse.previousButtonState[mouse] == 0) buttonReleaseNext[mouse] = 1;206                else CORE.Input.Mouse.currentButtonState[mouse] = 0;207                CORE.Input.Touch.currentTouchState[0] = CORE.Input.Mouse.currentButtonState[MOUSE_BUTTON_LEFT];208            }209        }210        else if (event->type == DOLLY_INPUT_EVENT_SCROLL)211        {212            // Thousandths of a pixel, line or page toward later content; raylib counts lines up.213            float lines = (float)event->y/1000.0f;214            if (event->action == DOLLY_SCROLL_UNIT_PIXEL) lines /= 100.0f;215            else if (event->action == DOLLY_SCROLL_UNIT_PAGE) lines *= 3.0f;216            CORE.Input.Mouse.currentWheelMove.y -= lines;217        }218        else if (event->type == DOLLY_INPUT_EVENT_FOCUS)219        {220            if (event->action) CORE.Window.flags &= ~FLAG_WINDOW_UNFOCUSED;221            else CORE.Window.flags |= FLAG_WINDOW_UNFOCUSED;222        }223    }224    225    // One touch@0 record into raylib's touch points as its own touch platforms226    // keep them: the fingers down in the order they came, each change a gesture227    // event, and the first finger also the mouse.228    static void DollyRaylibTouchRecord(const dolly_touch_record *record)229    {230        int index = 0;231        while ((index < CORE.Input.Touch.pointCount) && (CORE.Input.Touch.pointId[index] != (int)record->id)) index++;232        if (index == CORE.Input.Touch.pointCount)233        {234            if ((record->phase != DOLLY_TOUCH_DOWN) || (index == MAX_TOUCH_POINTS)) return;235            CORE.Input.Touch.pointId[index] = (int)record->id;236            CORE.Input.Touch.pointCount++;237        }238        CORE.Input.Touch.position[index] = (Vector2){ (float)record->x, (float)record->y };239    #if SUPPORT_GESTURES_SYSTEM240        GestureEvent gesture = { 0 };241        gesture.touchAction = (record->phase == DOLLY_TOUCH_DOWN)? TOUCH_ACTION_DOWN :242            (record->phase == DOLLY_TOUCH_MOVE)? TOUCH_ACTION_MOVE : (record->phase == DOLLY_TOUCH_UP)? TOUCH_ACTION_UP : TOUCH_ACTION_CANCEL;243        gesture.pointCount = CORE.Input.Touch.pointCount;244        for (int i = 0; i < gesture.pointCount; i++)245        {246            gesture.pointId[i] = CORE.Input.Touch.pointId[i];247            gesture.position[i] = (Vector2){ CORE.Input.Touch.position[i].x/(float)GetScreenWidth(),248                CORE.Input.Touch.position[i].y/(float)GetScreenHeight() };249        }250        ProcessGestureEvent(gesture);251    #endif252        if ((record->phase == DOLLY_TOUCH_UP) || (record->phase == DOLLY_TOUCH_CANCEL))253        {254            for (int i = index; i < CORE.Input.Touch.pointCount - 1; i++)255            {256                CORE.Input.Touch.pointId[i] = CORE.Input.Touch.pointId[i + 1];257                CORE.Input.Touch.position[i] = CORE.Input.Touch.position[i + 1];258            }259            CORE.Input.Touch.pointCount--;260        }261        // A tap inside one frame still reads as down for a frame, as keys do.262        if (CORE.Input.Touch.pointCount > 0) CORE.Input.Touch.currentTouchState[MOUSE_BUTTON_LEFT] = 1;263        else if (CORE.Input.Touch.previousTouchState[MOUSE_BUTTON_LEFT] == 0) touchReleaseNext = 1;264        else CORE.Input.Touch.currentTouchState[MOUSE_BUTTON_LEFT] = 0;265        if (index == 0) CORE.Input.Mouse.currentPosition = (Vector2){ (float)record->x, (float)record->y };266    }267    268    bool WindowShouldClose(void)269    {270        if (CORE.Window.ready) return CORE.Window.shouldClose;271        else return true;272    }273    274    void ToggleFullscreen(void) { TRACELOG(LOG_WARNING, "ToggleFullscreen() not available on target platform"); }275    void ToggleBorderlessWindowed(void) { TRACELOG(LOG_WARNING, "ToggleBorderlessWindowed() not available on target platform"); }276    void MaximizeWindow(void) { TRACELOG(LOG_WARNING, "MaximizeWindow() not available on target platform"); }277    void MinimizeWindow(void) { TRACELOG(LOG_WARNING, "MinimizeWindow() not available on target platform"); }278    void RestoreWindow(void) { TRACELOG(LOG_WARNING, "RestoreWindow() not available on target platform"); }279    void SetWindowState(unsigned int flags) { TRACELOG(LOG_WARNING, "SetWindowState() not available on target platform"); }280    void ClearWindowState(unsigned int flags) { TRACELOG(LOG_WARNING, "ClearWindowState() not available on target platform"); }281    void SetWindowIcon(Image image) { TRACELOG(LOG_WARNING, "SetWindowIcon() not available on target platform"); }282    void SetWindowIcons(Image *images, int count) { TRACELOG(LOG_WARNING, "SetWindowIcons() not available on target platform"); }283    void SetWindowTitle(const char *title) { CORE.Window.title = title; }284    void SetWindowPosition(int x, int y) { TRACELOG(LOG_WARNING, "SetWindowPosition() not available on target platform"); }285    void SetWindowMonitor(int monitor) { TRACELOG(LOG_WARNING, "SetWindowMonitor() not available on target platform"); }286    void SetWindowMinSize(int width, int height) { CORE.Window.screenMin.width = width; CORE.Window.screenMin.height = height; }287    void SetWindowMaxSize(int width, int height) { CORE.Window.screenMax.width = width; CORE.Window.screenMax.height = height; }288    void SetWindowSize(int width, int height) { TRACELOG(LOG_WARNING, "SetWindowSize() not available on target platform"); }289    void SetWindowOpacity(float opacity) { TRACELOG(LOG_WARNING, "SetWindowOpacity() not available on target platform"); }290    void SetWindowFocused(void) { TRACELOG(LOG_WARNING, "SetWindowFocused() not available on target platform"); }291    void *GetWindowHandle(void) { return NULL; }292    int GetMonitorCount(void) { return 1; }293    int GetCurrentMonitor(void) { return 0; }294    Vector2 GetMonitorPosition(int monitor) { return (Vector2){ 0, 0 }; }295    int GetMonitorWidth(int monitor) { return CORE.Window.display.width; }296    int GetMonitorHeight(int monitor) { return CORE.Window.display.height; }297    int GetMonitorPhysicalWidth(int monitor) { return 0; }298    int GetMonitorPhysicalHeight(int monitor) { return 0; }299    int GetMonitorRefreshRate(int monitor) { return 60; }300    const char *GetMonitorName(int monitor) { return "Dolly"; }301    Vector2 GetWindowPosition(void) { return (Vector2){ 0, 0 }; }302    Vector2 GetWindowScaleDPI(void) { return (Vector2){ 1.0f, 1.0f }; }303    void SetClipboardText(const char *text) { TRACELOG(LOG_WARNING, "SetClipboardText() not available on target platform"); }304    const char *GetClipboardText(void) { return NULL; }305    Image GetClipboardImage(void) { Image image = { 0 }; return image; }306    307    void ShowCursor(void)308    {309        if (platform.window) dolly_display_set_cursor(platform.surface.generation, DOLLY_DISPLAY_CURSOR_DEFAULT);310        CORE.Input.Mouse.cursorHidden = false;311    }312    313    void HideCursor(void)314    {315        if (platform.window) dolly_display_set_cursor(platform.surface.generation, DOLLY_DISPLAY_CURSOR_HIDDEN);316        CORE.Input.Mouse.cursorHidden = true;317    }318    319    void EnableCursor(void)320    {321        if (platform.window) dolly_input_set_pointer_relative(platform.input, 0);322        ShowCursor();323        CORE.Input.Mouse.cursorLocked = false;324    }325    326    void DisableCursor(void)327    {328        if (platform.window) dolly_input_set_pointer_relative(platform.input, 1);329        HideCursor();330        CORE.Input.Mouse.cursorLocked = true;331    }332    333    // Presents raylib's frame and waits for the page's next animation frame.334    void SwapScreenBuffer(void)335    {336        if (!platform.window) return;337        dolly_display_frame frame = { 0 };338        if ((dolly_display_begin_frame(platform.surface.generation, &frame) == 0) &&339            (frame.pixel_format == DOLLY_DISPLAY_PIXEL_RGBA8) && ((int)frame.width == CORE.Window.render.width) &&340            ((int)frame.height == CORE.Window.render.height) && ((size_t)frame.stride*frame.height <= frame.capacity))341        {342            rlCopyFramebuffer(0, 0, CORE.Window.render.width, CORE.Window.render.height, PIXELFORMAT_UNCOMPRESSED_R8G8B8A8, frame.pixels);343            dolly_display_present(platform.surface.generation, frame.buffer_index);344        }345        dolly_display_wait_frame(platform.surface.generation, &platform.animationFrame, 100.0);346    }347    348    double GetTime(void)349    {350        return MonotonicSeconds() - platform.start;351    }352    353    void OpenURL(const char *url) { TRACELOG(LOG_WARNING, "OpenURL() not available on target platform"); }354    int SetGamepadMappings(const char *mappings) { return 0; }355    void SetGamepadVibration(int gamepad, float leftMotor, float rightMotor, float duration) { }356    357    void SetMousePosition(int x, int y)358    {359        CORE.Input.Mouse.currentPosition = (Vector2){ (float)x, (float)y };360        CORE.Input.Mouse.previousPosition = CORE.Input.Mouse.currentPosition;361    }362    363    void SetMouseCursor(int cursor)364    {365        static const uint32_t cursors[] = { DOLLY_DISPLAY_CURSOR_DEFAULT, DOLLY_DISPLAY_CURSOR_DEFAULT, DOLLY_DISPLAY_CURSOR_TEXT,366            DOLLY_DISPLAY_CURSOR_CROSSHAIR, DOLLY_DISPLAY_CURSOR_POINTER, DOLLY_DISPLAY_CURSOR_EW_RESIZE, DOLLY_DISPLAY_CURSOR_NS_RESIZE,367            DOLLY_DISPLAY_CURSOR_NWSE_RESIZE, DOLLY_DISPLAY_CURSOR_NESW_RESIZE, DOLLY_DISPLAY_CURSOR_MOVE, DOLLY_DISPLAY_CURSOR_NOT_ALLOWED };368        if (platform.window && (cursor >= 0) && (cursor < (int)(sizeof(cursors)/sizeof(cursors[0]))))369        {370            dolly_display_set_cursor(platform.surface.generation, cursors[cursor]);371            CORE.Input.Mouse.cursor = cursor;372        }373    }374    375    const char *GetKeyName(int key) { return ""; }376    377    void PollInputEvents(void)378    {379    #if SUPPORT_GESTURES_SYSTEM380        UpdateGestures();381    #endif382        CORE.Input.Keyboard.keyPressedQueueCount = 0;383        CORE.Input.Keyboard.charPressedQueueCount = 0;384        for (int i = 0; i < MAX_KEYBOARD_KEYS; i++)385        {386            CORE.Input.Keyboard.previousKeyState[i] = CORE.Input.Keyboard.currentKeyState[i];387            CORE.Input.Keyboard.keyRepeatInFrame[i] = 0;388            if (keyReleaseNext[i]) CORE.Input.Keyboard.currentKeyState[i] = keyReleaseNext[i] = 0;389        }390        for (int i = 0; i < MAX_MOUSE_BUTTONS; i++)391        {392            CORE.Input.Mouse.previousButtonState[i] = CORE.Input.Mouse.currentButtonState[i];393            if (buttonReleaseNext[i]) CORE.Input.Mouse.currentButtonState[i] = buttonReleaseNext[i] = 0;394        }395        CORE.Input.Mouse.previousPosition = CORE.Input.Mouse.currentPosition;396        CORE.Input.Mouse.previousWheelMove = CORE.Input.Mouse.currentWheelMove;397        CORE.Input.Mouse.currentWheelMove = (Vector2){ 0.0f, 0.0f };398        for (int i = 0; i < MAX_TOUCH_POINTS; i++) CORE.Input.Touch.previousTouchState[i] = CORE.Input.Touch.currentTouchState[i];399        if (touchReleaseNext) CORE.Input.Touch.currentTouchState[MOUSE_BUTTON_LEFT] = touchReleaseNext = 0;400    401        if (!platform.window) return;402        dolly_input_event event;403        while (dolly_input_next_event(platform.input, &event, 0.0) > 0) DollyRaylibInputEvent(&event);404        int count = DOLLY_TOUCH_READ_RECORDS;405        while (platform.touch && (count == DOLLY_TOUCH_READ_RECORDS))406        {407            dolly_touch_record records[DOLLY_TOUCH_READ_RECORDS];408            count = dolly_touch_read(platform.touch, records, DOLLY_TOUCH_READ_RECORDS, 0.0);409            for (int i = 0; i < count; i++) DollyRaylibTouchRecord(&records[i]);410            if (count < 0)411            {412                dolly_touch_release(platform.touch);413                platform.touch = 0;414            }415        }416    }417    418    int InitPlatform(void)419    {420        if (rlGetVersion() != RL_OPENGL_SOFTWARE)421        {422            TRACELOG(LOG_FATAL, "PLATFORM: DOLLY: raylib must be built with its software renderer (GRAPHICS_API_OPENGL_SOFTWARE)");423            return -1;424        }425        platform.start = MonotonicSeconds();426    427        // A hidden window (FLAG_WINDOW_HIDDEN), or a program that holds the display428        // already, presents raylib's frames itself.429        if (!(CORE.Window.flags & FLAG_WINDOW_HIDDEN) && (dolly_display_acquire(&platform.surface) == 0))430        {431            if (dolly_input_acquire(&platform.input) != 0)432            {433                dolly_display_release(platform.surface.generation);434                TRACELOG(LOG_WARNING, "PLATFORM: DOLLY: no input: raylib renders to memory");435            }436            else437            {438                platform.window = 1;439                // Fingers where the page has a touchscreen for the program; without440                // one the program goes on with the mouse and keys.441                if (dolly_touch_acquire(&platform.touch) != 0) platform.touch = 0;442                CORE.Window.display.width = (int)platform.surface.width;443                CORE.Window.display.height = (int)platform.surface.height;444                if (CORE.Window.screen.width == 0) CORE.Window.screen.width = (int)platform.surface.width;445                if (CORE.Window.screen.height == 0) CORE.Window.screen.height = (int)platform.surface.height;446                if (((int)platform.surface.width != CORE.Window.screen.width) || ((int)platform.surface.height != CORE.Window.screen.height))447                {448                    if (dolly_display_set_size(platform.surface.generation, (uint32_t)CORE.Window.screen.width,449                        (uint32_t)CORE.Window.screen.height, &platform.surface) != 0)450                    {451                        TRACELOG(LOG_FATAL, "PLATFORM: DOLLY: the display cannot show %i x %i", CORE.Window.screen.width, CORE.Window.screen.height);452                        if (platform.touch) dolly_touch_release(platform.touch);453                        dolly_input_release(platform.input);454                        dolly_display_release(platform.surface.generation);455                        platform.window = 0;456                        return -1;457                    }458                }459            }460        }461    462        CORE.Window.render.width = CORE.Window.screen.width;463        CORE.Window.render.height = CORE.Window.screen.height;464        CORE.Window.currentFbo.width = CORE.Window.render.width;465        CORE.Window.currentFbo.height = CORE.Window.render.height;466        CORE.Window.ready = true;467        CORE.Storage.basePath = GetWorkingDirectory();468        InitTimer();469        TRACELOG(LOG_INFO, "PLATFORM: DOLLY: %s, %i x %i", platform.window ? "display and input" : "memory only",470            CORE.Window.screen.width, CORE.Window.screen.height);471        return 0;472    }473    474    void ClosePlatform(void)475    {476        if (platform.window)477        {478            if (platform.touch) dolly_touch_release(platform.touch);479            dolly_input_release(platform.input);480            dolly_display_release(platform.surface.generation);481        }482        platform.window = 0;483        platform.touch = 0;484    }485FILE /usr/src/dolly/raylib/dolly-raylib.c486    #include "dolly-raylib.h"487    488    #include <rlgl.h>489    490    #include <errno.h>491    #include <stddef.h>492    #include <string.h>493    494    // raylib's Dolly backend (rcore_dolly.c) keeps raylib's key, character and495    // mouse state from the records it is handed.496    void DollyRaylibInputEvent(const dolly_input_event *event);497    498    int dolly_raylib_open_sized(dolly_raylib *context, const char *title,499                                uint32_t max_width, uint32_t max_height) {500      if (context == NULL || max_width == 0 || max_height == 0) return -EINVAL;501      memset(context, 0, sizeof(*context));502      int status = dolly_display_acquire(&context->surface);503      if (status != 0) return status;504      status = dolly_input_acquire(&context->input);505      if (status != 0) {506        dolly_display_release(context->surface.generation);507        memset(context, 0, sizeof(*context));508        return status;509      }510    511      uint32_t width = context->surface.width;512      uint32_t height = context->surface.height;513      if (width > max_width || height > max_height) {514        if ((uint64_t)width * max_height > (uint64_t)height * max_width) {515          height = (uint32_t)((uint64_t)height * max_width / width);516          width = max_width;517        } else {518          width = (uint32_t)((uint64_t)width * max_height / height);519          height = max_height;520        }521        if (width == 0) width = 1;522        if (height == 0) height = 1;523        status = dolly_display_set_size(context->surface.generation, width, height,524                                        &context->surface);525        if (status != 0) {526          dolly_input_release(context->input);527          dolly_display_release(context->surface.generation);528          memset(context, 0, sizeof(*context));529          return status;530        }531      }532    533      InitWindow((int)context->surface.width, (int)context->surface.height, title);534      if (!IsWindowReady()) {535        dolly_input_release(context->input);536        dolly_display_release(context->surface.generation);537        memset(context, 0, sizeof(*context));538        return -EIO;539      }540      SetTraceLogLevel(LOG_WARNING);541      context->open = 1;542      return 0;543    }544    545    int dolly_raylib_open(dolly_raylib *context, const char *title) {546      return dolly_raylib_open_sized(context, title, 800, 450);547    }548    549    int dolly_raylib_end_frame(dolly_raylib *context) {550      if (context == NULL || !context->open) return -EINVAL;551      // The program holds the display, so raylib's EndDrawing only flushes its552      // render batch and times the frame; the frame is presented here.553      EndDrawing();554    555      dolly_display_frame frame;556      int status = dolly_display_begin_frame(context->surface.generation, &frame);557      if (status == 0 && frame.pixel_format == DOLLY_DISPLAY_PIXEL_RGBA8 &&558          frame.width == context->surface.width &&559          frame.height == context->surface.height &&560          (size_t)frame.stride * frame.height <= frame.capacity) {561        rlCopyFramebuffer(0, 0, (int)frame.width, (int)frame.height,562                          PIXELFORMAT_UNCOMPRESSED_R8G8B8A8, frame.pixels);563        status = dolly_display_present(context->surface.generation,564                                       frame.buffer_index);565      } else if (status == 0) {566        status = -EIO;567      }568      return status;569    }570    571    int dolly_raylib_wait_frame(dolly_raylib *context,572                                double timeout_milliseconds) {573      if (context == NULL || !context->open) return -EINVAL;574      return dolly_display_wait_frame(context->surface.generation,575                                      &context->animation_frame_sequence,576                                      timeout_milliseconds);577    }578    579    int dolly_raylib_set_cursor(dolly_raylib *context, uint32_t cursor) {580      if (context == NULL || !context->open) return -EINVAL;581      return dolly_display_set_cursor(context->surface.generation, cursor);582    }583    584    int dolly_raylib_next_event(dolly_raylib *context, dolly_input_event *event,585                                double timeout_milliseconds) {586      if (context == NULL || !context->open) return -EINVAL;587      int status = dolly_input_next_event(context->input, event, timeout_milliseconds);588      if (status > 0) DollyRaylibInputEvent(event);589      return status;590    }591    592    int dolly_raylib_close(dolly_raylib *context) {593      if (context == NULL || !context->open) return -EINVAL;594      CloseWindow();595      dolly_input_release(context->input);596      int status = dolly_display_release(context->surface.generation);597      memset(context, 0, sizeof(*context));598      return status;599    }600    601    int dolly_raylib_code_is(const dolly_input_event *event, const char *code) {602      if (event == NULL || code == NULL || event->type != DOLLY_INPUT_EVENT_KEY)603        return 0;604      size_t length = strlen(code);605      return event->code_length == length &&606             memcmp(event->data + event->key_length, code, length) == 0;607    }608FILE /usr/src/dolly/raylib/dolly-raylib.h609    #ifndef DOLLY_RAYLIB_H610    #define DOLLY_RAYLIB_H611    612    #include <dolly/display.h>613    #include <dolly/input.h>614    #include <raylib.h>615    616    typedef struct {617      dolly_display_surface surface;618      uint64_t input;619      uint32_t animation_frame_sequence;620      int open;621    } dolly_raylib;622    623    // For a program that holds the display itself: open acquires the display and624    // input before InitWindow, so raylib renders to memory; end_frame presents its625    // frame and next_event hands each record to raylib's key and mouse state too.626    // The default open caps software rendering at 800x450; callers can choose627    // another upper bound while retaining the browser viewport ratio.628    int dolly_raylib_open(dolly_raylib *context, const char *title);629    int dolly_raylib_open_sized(dolly_raylib *context, const char *title,630                                uint32_t max_width, uint32_t max_height);631    int dolly_raylib_end_frame(dolly_raylib *context);632    int dolly_raylib_wait_frame(dolly_raylib *context, double timeout_milliseconds);633    int dolly_raylib_set_cursor(dolly_raylib *context, uint32_t cursor);634    int dolly_raylib_next_event(dolly_raylib *context, dolly_input_event *event,635                                double timeout_milliseconds);636    int dolly_raylib_close(dolly_raylib *context);637    int dolly_raylib_code_is(const dolly_input_event *event, const char *code);638    639    #endif640SLOP tar -xf /tmp/raylib.tar -C /641SLOP CWD /usr/src/dolly/raylib make -f /usr/src/dolly/raylib/raylib.mk642643EXPORTS LIB    raylib       /usr/lib/libraylib.a644EXPORTS LIB    dolly-raylib /usr/lib/libdolly-raylib.a645EXPORTS HEADER raylib       /usr/include/raylib.h646EXPORTS HEADER dolly-raylib /usr/include/dolly/raylib.h647FILE /usr/include/raymath.h648FILE /usr/include/rlgl.h649FILE /usr/share/licenses/raylib/LICENSE650SLOP rm -rf /tmp/raylib.tar /usr/src/raylib /usr/src/dolly/raylib651