1DOLLY 72TOOLCHAIN gamedev-sdk3REQUIRES HOST runtime@04REQUIRES HOST display@05REQUIRES HOST input@06REQUIRES HOST download@07REQUIRES HOST http@08REQUIRES HOST snapshot@09REQUIRES HOST upload@01011FROM /v0.1.2/Dollyfile-system cb003619fa38f3340386739e0df6a500c95f5ff040b1efb6804461adf294b25912REQUIRES HEADER libc13REQUIRES HEADER display14REQUIRES HEADER input15REQUIRES TOOL ar16REQUIRES TOOL cc17REQUIRES TOOL make18REQUIRES TOOL mkdir19REQUIRES TOOL rm20REQUIRES TOOL tar212223SOURCE /v0.1.2/dist/static/gamedev/raylib.tar b16dd083b9205e14f8b79a1d91c934b579c9a92bcb4e3af0e374f3e71dcf82d3 /tmp/raylib.tar24SOURCE /v0.1.2/dist/static/gamedev/box3d.tar 5a502138e8f7b47c5994bdd279e9dcddeae0b8e147e3b92ab79b723bd07e4377 /tmp/box3d.tar2526FILE /usr/src/dolly/gamedev/sdk.mk27 CC := cc28 AR := ar29 RAYLIB_SOURCE := /usr/src/raylib/src30 RAYLIB_MODULES := rcore rshapes rtextures rtext rmodels31 RAYLIB_OBJECTS := $(patsubst %,/usr/src/raylib/build/%.o,$(RAYLIB_MODULES))32 BOX3D_SOURCE := /usr/src/box3d/src33 BOX3D_SOURCES := $(filter-out $(BOX3D_SOURCE)/timer.c,$(wildcard $(BOX3D_SOURCE)/*.c))34 BOX3D_OBJECTS := $(patsubst $(BOX3D_SOURCE)/%.c,/usr/src/box3d/build/%.o,$(BOX3D_SOURCES))35 MATH_COMPAT_OBJECT := /usr/src/dolly/gamedev/build/math-compat.o36 37 .PHONY: all38 39 all: /usr/lib/libm.a /usr/lib/libraylib.a /usr/lib/libbox3d.a /usr/lib/libdolly-raylib.a40 41 /usr/src/raylib/build/%.o: $(RAYLIB_SOURCE)/%.c42 mkdir -p /usr/src/raylib/build43 $(CC) -std=gnu99 -O2 -D_GNU_SOURCE -DPLATFORM_MEMORY -DGRAPHICS_API_OPENGL_SOFTWARE -DSUPPORT_CUSTOM_FRAME_CONTROL=1 -DSW_FRAMEBUFFER_OUTPUT_BGRA=0 -fno-strict-aliasing -fno-builtin -I $(RAYLIB_SOURCE) -c $< -o $@44 45464748 /usr/src/raylib/build/rtext.o: $(RAYLIB_SOURCE)/rtext.c49 mkdir -p /usr/src/raylib/build50 $(CC) -std=gnu99 -O0 -D_GNU_SOURCE -DPLATFORM_MEMORY -DGRAPHICS_API_OPENGL_SOFTWARE -DSUPPORT_CUSTOM_FRAME_CONTROL=1 -DSW_FRAMEBUFFER_OUTPUT_BGRA=0 -fno-strict-aliasing -fno-builtin -I $(RAYLIB_SOURCE) -c $< -o $@51 52 /usr/lib/libraylib.a: $(RAYLIB_OBJECTS)53 $(AR) rcs $@ $(RAYLIB_OBJECTS)54 cp $(RAYLIB_SOURCE)/raylib.h /usr/include/raylib.h55 cp $(RAYLIB_SOURCE)/raymath.h /usr/include/raymath.h56 cp $(RAYLIB_SOURCE)/rlgl.h /usr/include/rlgl.h57 58 /usr/src/box3d/build/%.o: $(BOX3D_SOURCE)/%.c59 mkdir -p /usr/src/box3d/build60 $(CC) -std=gnu17 -O2 -fno-builtin -U__SIZEOF_INT128__ -DBOX3D_DISABLE_SIMD -I /usr/src/box3d/include -I $(BOX3D_SOURCE) -c $< -o $@61 62 /usr/src/box3d/build/platform.o: /usr/src/dolly/gamedev/box3d-platform.c63 mkdir -p /usr/src/box3d/build64 $(CC) -std=gnu17 -O2 -fno-builtin -U__SIZEOF_INT128__ -DBOX3D_DISABLE_SIMD -I /usr/src/box3d/include -I $(BOX3D_SOURCE) -c $< -o $@65 66 /usr/lib/libbox3d.a: $(BOX3D_OBJECTS) /usr/src/box3d/build/platform.o67 $(AR) rcs $@ $^68 mkdir -p /usr/include/box3d69 cp /usr/src/box3d/include/box3d/*.h /usr/include/box3d70 71 $(MATH_COMPAT_OBJECT): /usr/src/dolly/gamedev/math-compat.c72 mkdir -p /usr/src/dolly/gamedev/build73 $(CC) -std=c17 -O2 -fno-builtin -c $< -o $@74 75 /usr/lib/libm.a: $(MATH_COMPAT_OBJECT)76 $(AR) rcs $@ $^77 78 /usr/lib/libdolly-raylib.a: /usr/src/dolly/gamedev/dolly-raylib.c /usr/src/dolly/gamedev/dolly-raylib.h /usr/lib/libraylib.a79 mkdir -p /usr/include/dolly /usr/src/dolly/gamedev/build80 cp /usr/src/dolly/gamedev/dolly-raylib.h /usr/include/dolly/raylib.h81 $(CC) -std=c17 -O2 -fno-builtin -I /usr/src/dolly/gamedev -c /usr/src/dolly/gamedev/dolly-raylib.c -o /usr/src/dolly/gamedev/build/dolly-raylib.o82 $(AR) rcs $@ /usr/src/dolly/gamedev/build/dolly-raylib.o8384FILE /usr/src/dolly/gamedev/math-compat.c858687 88 int abs(int value) { return value < 0 ? -value : value; }89 float asinf(float value) { return (float)asin((double)value); }90 float atan2f(float left, float right) {91 return (float)atan2((double)left, (double)right);92 }93 float ceilf(float value) { return (float)ceil((double)value); }94 float fabsf(float value) { return (float)fabs((double)value); }95 float floorf(float value) { return (float)floor((double)value); }96 double fmax(double left, double right) {97 if (left != left) return right;98 if (right != right) return left;99 return left > right ? left : right;100 }101 double fmin(double left, double right) {102 if (left != left) return right;103 if (right != right) return left;104 return left < right ? left : right;105 }106 float fmodf(float left, float right) {107 return (float)fmod((double)left, (double)right);108 }109 float hypotf(float left, float right) {110 return (float)hypot((double)left, (double)right);111 }112 float powf(float left, float right) {113 return (float)pow((double)left, (double)right);114 }115 float roundf(float value) { return (float)round((double)value); }116 float sqrtf(float value) { return (float)sqrt((double)value); }117FILE /usr/src/dolly/gamedev/box3d-platform.c118119 120 // Dolly's Box3D target adapter replaces upstream timer.c. Box3D's built-in121 // scheduler links pthread primitives even when the normal one-worker world122 // never creates a thread. Dolly deliberately executes tasks serially inside123 // one Wasm userspace, so synchronization objects carry no host capability and124 // worker handles are inert. The scheduler's calling thread still drains every125 // queued task in b3SchedulerFinishTask.126 127128 129130131132 133 uint64_t b3GetTicks(void) {134 struct timespec now = {0};135 if (clock_gettime(CLOCK_MONOTONIC, &now) != 0) return 0;136 return (uint64_t)now.tv_sec * UINT64_C(1000000000) +137 (uint64_t)now.tv_nsec;138 }139 140 float b3GetMilliseconds(uint64_t ticks) {141 return (float)((double)(b3GetTicks() - ticks) / 1000000.0);142 }143 144 float b3GetMillisecondsAndReset(uint64_t *ticks) {145 const uint64_t now = b3GetTicks();146 const float elapsed = (float)((double)(now - *ticks) / 1000000.0);147 *ticks = now;148 return elapsed;149 }150 151 void b3Yield(void) {}152 void b3Sleep(int milliseconds) { (void)milliseconds; }153 154 struct b3Mutex { unsigned unused; };155 struct b3Semaphore { int count; };156 struct b3Thread { unsigned unused; };157 158 b3Mutex *b3CreateMutex(void) {159 return b3AllocZeroed(sizeof(b3Mutex));160 }161 162 void b3DestroyMutex(b3Mutex *mutex) {163 b3Free(mutex, sizeof(b3Mutex));164 }165 166 void b3LockMutex(b3Mutex *mutex) { (void)mutex; }167 void b3UnlockMutex(b3Mutex *mutex) { (void)mutex; }168 169 b3Semaphore *b3CreateSemaphore(int initial_count) {170 b3Semaphore *semaphore = b3Alloc(sizeof(b3Semaphore));171 semaphore->count = initial_count;172 return semaphore;173 }174 175 void b3DestroySemaphore(b3Semaphore *semaphore) {176 b3Free(semaphore, sizeof(b3Semaphore));177 }178 179 void b3WaitSemaphore(b3Semaphore *semaphore) {180 if (semaphore->count > 0) semaphore->count--;181 }182 183 void b3SignalSemaphore(b3Semaphore *semaphore) {184 semaphore->count++;185 }186 187 b3Thread *b3CreateThread(b3ThreadFunction *function, void *context,188 const char *name) {189 (void)function;190 (void)context;191 (void)name;192 return b3AllocZeroed(sizeof(b3Thread));193 }194 195 void b3JoinThread(b3Thread *thread) {196 b3Free(thread, sizeof(b3Thread));197 }198 199 // This deterministic djb2 variant is part of upstream timer.c rather than the200 // OS-independent core. Keep the exact algorithm when replacing that complete201 // translation unit so hull and mesh hashes stay compatible with upstream.202 uint32_t b3Hash(uint32_t hash, const uint8_t *data, int count) {203 uint32_t result = hash;204 int index = 0;205 while (index + 8 <= count) {206 uint64_t word;207 memcpy(&word, data + index, sizeof(word));208209 word = ((word & UINT64_C(0x00000000000000ff)) << 56) |210 ((word & UINT64_C(0x000000000000ff00)) << 40) |211 ((word & UINT64_C(0x0000000000ff0000)) << 24) |212 ((word & UINT64_C(0x00000000ff000000)) << 8) |213 ((word & UINT64_C(0x000000ff00000000)) >> 8) |214 ((word & UINT64_C(0x0000ff0000000000)) >> 24) |215 ((word & UINT64_C(0x00ff000000000000)) >> 40) |216 ((word & UINT64_C(0xff00000000000000)) >> 56);217218 result = (result << 5) + result + (uint32_t)word;219 result = (result << 5) + result + (uint32_t)(word >> 32);220 index += 8;221 }222 while (index < count) {223 result = (result << 5) + result + data[index];224 index++;225 }226 return result;227 }228FILE /usr/src/dolly/gamedev/dolly-raylib.c229230 231232 233234235236237238 239 // Upstream PLATFORM_MEMORY polls a Unix tty. Dolly supplies input through240 // dolly_input_next_event(), so satisfy those unreachable backend hooks241 // locally instead of growing the command ABI with a second input path.242 int tcgetattr(int descriptor, struct termios *attributes) {243 (void)descriptor;244 (void)attributes;245 errno = ENOTTY;246 return -1;247 }248 249 int tcsetattr(int descriptor, int action, const struct termios *attributes) {250 (void)descriptor;251 (void)action;252 (void)attributes;253 errno = ENOTTY;254 return -1;255 }256 257 int getchar(void) { return EOF; }258 259 int dolly_raylib_open_sized(dolly_raylib *context, const char *title,260 uint32_t max_width, uint32_t max_height) {261 if (context == NULL || max_width == 0 || max_height == 0) return -EINVAL;262 memset(context, 0, sizeof(*context));263 int status = dolly_display_acquire(&context->surface);264 if (status != 0) return status;265 status = dolly_input_acquire(&context->input);266 if (status != 0) {267 dolly_display_release(context->surface.generation);268 memset(context, 0, sizeof(*context));269 return status;270 }271 272 uint32_t width = context->surface.width;273 uint32_t height = context->surface.height;274 if (width > max_width || height > max_height) {275 if ((uint64_t)width * max_height > (uint64_t)height * max_width) {276 height = (uint32_t)((uint64_t)height * max_width / width);277 width = max_width;278 } else {279 width = (uint32_t)((uint64_t)width * max_height / height);280 height = max_height;281 }282 if (width == 0) width = 1;283 if (height == 0) height = 1;284 status = dolly_display_set_size(context->surface.generation, width, height,285 &context->surface);286 if (status != 0) {287 dolly_input_release(context->input);288 dolly_display_release(context->surface.generation);289 memset(context, 0, sizeof(*context));290 return status;291 }292 }293 294 InitWindow((int)context->surface.width, (int)context->surface.height, title);295 if (!IsWindowReady()) {296 dolly_input_release(context->input);297 dolly_display_release(context->surface.generation);298 memset(context, 0, sizeof(*context));299 return -EIO;300 }301 SetTraceLogLevel(LOG_WARNING);302 context->open = 1;303 return 0;304 }305 306 int dolly_raylib_open(dolly_raylib *context, const char *title) {307 return dolly_raylib_open_sized(context, title, 800, 450);308 }309 310 int dolly_raylib_end_frame(dolly_raylib *context) {311 if (context == NULL || !context->open) return -EINVAL;312 // SUPPORT_CUSTOM_FRAME_CONTROL makes EndDrawing flush raylib's render batch313 // without copying into PLATFORM_MEMORY's private presentation buffer or314 // sleeping. Dolly supplies both presentation and pacing below.315 EndDrawing();316 317 dolly_display_frame frame;318 int status = dolly_display_begin_frame(context->surface.generation, &frame);319 if (status == 0 && frame.pixel_format == DOLLY_DISPLAY_PIXEL_RGBA8 &&320 frame.width == context->surface.width &&321 frame.height == context->surface.height &&322 (size_t)frame.stride * frame.height <= frame.capacity) {323 rlCopyFramebuffer(0, 0, (int)frame.width, (int)frame.height,324 PIXELFORMAT_UNCOMPRESSED_R8G8B8A8, frame.pixels);325 status = dolly_display_present(context->surface.generation,326 frame.buffer_index);327 } else if (status == 0) {328 status = -EIO;329 }330 return status;331 }332 333 int dolly_raylib_wait_frame(dolly_raylib *context,334 double timeout_milliseconds) {335 if (context == NULL || !context->open) return -EINVAL;336 return dolly_display_wait_frame(context->surface.generation,337 &context->animation_frame_sequence,338 timeout_milliseconds);339 }340 341 int dolly_raylib_set_cursor(dolly_raylib *context, uint32_t cursor) {342 if (context == NULL || !context->open) return -EINVAL;343 return dolly_display_set_cursor(context->surface.generation, cursor);344 }345 346 int dolly_raylib_next_event(dolly_raylib *context, dolly_input_event *event,347 double timeout_milliseconds) {348 if (context == NULL || !context->open) return -EINVAL;349 return dolly_input_next_event(context->input, event, timeout_milliseconds);350 }351 352 int dolly_raylib_close(dolly_raylib *context) {353 if (context == NULL || !context->open) return -EINVAL;354 CloseWindow();355 dolly_input_release(context->input);356 int status = dolly_display_release(context->surface.generation);357 memset(context, 0, sizeof(*context));358 return status;359 }360 361 int dolly_raylib_code_is(const dolly_input_event *event, const char *code) {362 if (event == NULL || code == NULL || event->type != DOLLY_INPUT_EVENT_KEY)363 return 0;364 size_t length = strlen(code);365 return event->code_length == length &&366 memcmp(event->data + event->key_length, code, length) == 0;367 }368FILE /usr/src/dolly/gamedev/dolly-raylib.h369370371 372373374375 376 typedef struct {377 dolly_display_surface surface;378 uint64_t input;379 uint32_t animation_frame_sequence;380 int open;381 } dolly_raylib;382 383 // PLATFORM_MEMORY renders wholly inside Wasm. The adapter copies its completed384 // software frame directly into Dolly's inactive buffer without an intermediate385 // raylib Image. The default open caps software rendering at 800x450; callers386 // can choose another upper bound while retaining the browser viewport ratio.387 int dolly_raylib_open(dolly_raylib *context, const char *title);388 int dolly_raylib_open_sized(dolly_raylib *context, const char *title,389 uint32_t max_width, uint32_t max_height);390 int dolly_raylib_end_frame(dolly_raylib *context);391 int dolly_raylib_wait_frame(dolly_raylib *context, double timeout_milliseconds);392 int dolly_raylib_set_cursor(dolly_raylib *context, uint32_t cursor);393 int dolly_raylib_next_event(dolly_raylib *context, dolly_input_event *event,394 double timeout_milliseconds);395 int dolly_raylib_close(dolly_raylib *context);396 int dolly_raylib_code_is(const dolly_input_event *event, const char *code);397 398399SLOP tar \400 -xf /tmp/raylib.tar \401 -C /402SLOP tar \403 -xf /tmp/box3d.tar \404 -C /405SLOP CWD /usr/src/dolly/gamedev make \406 -f /usr/src/dolly/gamedev/sdk.mk407408FILE /usr/include/raymath.h409FILE /usr/include/rlgl.h410FILE /usr/share/licenses/raylib/LICENSE411FILE /usr/share/licenses/box3d/LICENSE412FOLDER /usr/src/raylib413FOLDER /usr/src/box3d414415EXPORTS LIB raylib /usr/lib/libraylib.a416EXPORTS LIB box3d /usr/lib/libbox3d.a417EXPORTS LIB dolly-raylib /usr/lib/libdolly-raylib.a418EXPORTS LIB m /usr/lib/libm.a419EXPORTS HEADER /usr/include/raylib.h420EXPORTS HEADER /usr/include/box3d421EXPORTS HEADER /usr/include/dolly/raylib.h422423SLOP rm \424 -rf \425 /tmp/box3d.tar \426 /usr/src/raylib/build \427 /usr/src/box3d/build \428 /usr/src/dolly/gamedev/build \429 /tmp/raylib.tar430431ENTRY /bin/foreground -i /bin/slop432