1DOLLY 72PACKAGE raylib3REQUIRES HOST runtime@04REQUIRES HOST display@05REQUIRES HOST input@06REQUIRES HOST touch@07891011121314FROM /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 4445 $(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.616263FILE /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.7576777879 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 };232233 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);244245 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 {372373 UpdateGestures();374375 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.c479480 481482 483484485486 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.h602603604 605606607608 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 632633SLOP 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 /usr/include/raylib.h639EXPORTS HEADER /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