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