1DOLLY 72PACKAGE raylib3REQUIRES HOST runtime@04REQUIRES HOST display@05REQUIRES HOST input@06REQUIRES HOST touch@07891011121314FROM /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 44454647 $(BUILD)/rtext.o: $(SOURCE)/rtext.c48 mkdir -p $(BUILD)49 $(CC) $(subst -O2,-O0,$(FLAGS)) -c $< -o $@50 5152 $(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.686970FILE /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.8283848586 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 };239240 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);251252 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 {379380 UpdateGestures();381382 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.c486487 488489 490491492493 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.h609610611 612613614615 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 639640SLOP 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 /usr/include/raylib.h646EXPORTS HEADER /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