{"id":32514138,"url":"https://github.com/aras-p/playdators","last_synced_at":"2025-10-27T23:28:59.114Z","repository":{"id":318731111,"uuid":"1061825567","full_name":"aras-p/playdators","owner":"aras-p","description":"Simple 3D \"engine\" for Playdate console","archived":false,"fork":false,"pushed_at":"2025-10-12T15:39:55.000Z","size":1841,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2025-10-13T16:57:20.033Z","etag":null,"topics":["playdate"],"latest_commit_sha":null,"homepage":"","language":"C","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"unlicense","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/aras-p.png","metadata":{"files":{"readme":"readme.md","changelog":null,"contributing":null,"funding":null,"license":"license.md","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2025-09-22T12:42:01.000Z","updated_at":"2025-10-13T14:33:05.000Z","dependencies_parsed_at":"2025-10-13T16:57:21.710Z","dependency_job_id":"33a9655c-ab7b-4a0d-9a63-146e4938d5d6","html_url":"https://github.com/aras-p/playdators","commit_stats":null,"previous_names":["aras-p/playdators"],"tags_count":null,"template":false,"template_full_name":null,"purl":"pkg:github/aras-p/playdators","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/aras-p%2Fplaydators","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/aras-p%2Fplaydators/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/aras-p%2Fplaydators/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/aras-p%2Fplaydators/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/aras-p","download_url":"https://codeload.github.com/aras-p/playdators/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/aras-p%2Fplaydators/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":281361324,"owners_count":26487879,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-10-27T02:00:05.855Z","response_time":61,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["playdate"],"created_at":"2025-10-27T23:28:57.787Z","updated_at":"2025-10-27T23:28:59.106Z","avatar_url":"https://github.com/aras-p.png","language":"C","funding_links":[],"categories":[],"sub_categories":[],"readme":"﻿# PlayDators - simple 3D engine for Playdate\n\n ![](/images/playdators_choco_2.png?raw=true \"\")\n\nSimple 3D software rasterizer and helping code for [Playdate](https://play.date/) console. The same code can also be built for PC. Everything is in pure C, there are no Lua bits (yet?).\n\n_\"Dators\" means \"computer\" in Latvian. I don't know Latvian, but I like the word._\n\n ### Sample application / \"game\"\n\n`src/main.c` contains a simple \"3D game\", where Chocomel the dog (from **Blender Studio DOG WALK game** - [project page](https://studio.blender.org/projects/dogwalk/), [steam page](https://store.steampowered.com/app/3775050/DOGWALK/)) has to run along a 3D curve in space, jumping over or digging through obstacles.\n\n**Web build of the sample game**: https://aras-p.github.io/playdators/ (1MB). \u003cbr/\u003e\n**Playdate build of the game**: https://aras-p.info/files/games/2025_playdators/PlayDators_Sample.pdx.zip (1MB) -- should work on Playdate device and the simulator on Windows.\n\n| | |\n|---|---|\n| ![](/images/playdators_choco_0.png?raw=true \"\") | ![](/images/playdators_choco_1.png?raw=true \"\") |\n| ![](/images/playdators_choco_3.png?raw=true \"\") | ![](/images/playdators_choco_4.png?raw=true \"\") |\n\nAll the meshes there are from the [Dog Walk](https://studio.blender.org/projects/dogwalk/) project, and as such they are not particularly optimized for either Playdate, nor\nfor a graphics engine that has no textures. I applied Blender's Decimate modifier on them at 15-20% of original poly count, exported, and that's it.\n\nThe music and sounds are from the Dog Walk project as well, converted to IMA ADPCM in Audacity.\n\nThe game tends to render 500-1000 visible triangles as well as a bunch of triangle edges, at runs at 45-50 frames per second on the Playdate device.\n\nControls:\n- Right: move Chocomel,\n- Up: jump (can only do that while running),\n- B: dig through an obstacle,\n- Crank / mouse wheel: orbit the camera a bit.\n- A: toggle rendering between simple dithering and blue-noise dithering.\n\n### Graphics\n\n`src/render.h` contains a tiny 3D rasterizer.\n\n* Meshes are either created from code procedurally (`mesh_create`) or loaded from a custom binary format (`mesh_load_from_file`). Meshes contain:\n\t* Vertex positions,\n\t\t* A single mesh can have multiple \"frames\" of animation, where vertex positions can vary for each frame.\n\t* Triangle index buffer (3 16-bit vertex indices per triangle),\n\t* Optional triangle colors (1 byte per triangle),\n\t* Optional edge flags, to indicate which edges of triangle should be drawn when drawing wireframe.\n\t* Optional texture coordinates (though they are fairly useless currently).\n* A \"3D scene\" is composed of `MeshInstance` objects, which point to the mesh as well as per-instance parameters:\n\t* 3D transform matrix,\n\t* Color (single float),\n\t* Animation frame index,\n\t* Drawing flags:\n\t\t* Solid: uses per-instance color, combined with mesh per-face color if present,\n\t\t* Solit and lit: additionally modulates the color by a wrapped diffuse term between view-space lighting direction and view-space\n\t\t  triangle normal,\n\t\t* Wireframe: draw triangle edges. Per-mesh data can be present to indicate which edges to draw.\n\t\t* Silhouette wireframe: draw edges of \"silhouette\" faces. Mesh face adjacency is computed on first use, then\n\t\t  edges are drawn between neighboring faces where one face is visible and the other is not.\n\t* Sorting bias: additional value to to view space distance while sorting mesh instances for painter's algorithm.\n* Objects in the scene are sorted back-to-front and drawn in that order (with optional per-instance sorting fudge), and then triangles\n  each mesh are sorted back-to-front and drawn in that order too. _There is no depth buffer_, so sorting artifacts are entirely possible!\n* Everything is rendered using either fixed dithering patterns, or dithering through a premade blue noise texture.\n* Coordinate conventions are like in Unity game engine (left handed, Y up): +X to the right, +Y up, +Z goes forward into the screen.\n* A **Blender export add-on** is in `blender/addons` folder. It can be used to export meshes into a file format understood by\n  `mesh_load_from_file`.\n\n### Platform abstaction\n\nIn order for the code to work on both the Playdate as well as PC, there is platform abstaction under `src/platform.h`:\n\n* `plat_file_` functions for working with files, similar to C stdio.\n* `plat_time_` functions for querying time.\n* `plat_sound_` functions for loading IMA ADPCM compressed WAV files and playing them back, including looping and volume control.\n  Multiple sounds can be played at once.\n* `plat_input_` functions for querying buttons and crank (on PC maps to mouse scroll wheel) input.\n* `plat_malloc` and related functions for memory allocation.\n\n### Math\n\n`src/mathlib.h` contains a tiny \"math library\" for what was needed in this code. Major parts:\n* `float3` struct and `v3_` functions for working with 3D vectors,\n* `xform` struct `xform_` functions for working with 3D transforms (3x3 rotation matrix expressed as three coordinate axes, plus translation vector),\n* `XorShift32` based random number generator,\n* Various math functions like `min`, `max`, `clamp`, `saturate`, `lerp`, `smoothstep` and so on.\n* Float to half precision (FP16) conversion: `float_to_half`, `float_to_half_topbits` that map to built-in Playdate CPU instruction.\n\n### CMake build system\n\nThe build is done with CMake, and I only ever tested it on Windows. There, just open the folder in Visual Studio (that's the only IDE I tested; and I only tested VS2022 version).\nThere will be several platforms in the platform dropdown: regular `x64` is for PC build, platforms with `(Playdate)` are for Playdate device build, and `(Playdate Sim)` is for\nPlaydate simulator build.\n\n`Source` folder is expected to have data files; some of these will be automatically processed by Playdate SDK tools while doing a build (e.g. PNG files will get converted to `.pdi`; WAV files\nto `.pda` and so on).\n\nBuilding for the web with Emscripten:\n- Have Emscripten [installed and the SDK activated](https://emscripten.org/docs/getting_started/downloads.html) on the command line.\n  I have tested with Emscripten 4.0.16 (2025 Oct).\n- Change current directory to this folder,\n- `cmake --preset emscripten-release`,\n- `cmake --build --preset em-release`\n- Built files will be under `build/emscripten_release` folder.\n- In order to test them locally in the browser, easiest to run a web server from that folder: `cd build\\emscripten-release` and\n  `python -m http.server`, then open `localhost:8000` in your browser.\n\nMost of the code layout and structure is taken from [Everybody Wants to Crank the World](https://github.com/aras-p/demo-pd-cranktheworld)\ndemo (2024) and [Surface-Stable Fractal Dithering on Playdate](https://github.com/aras-p/playdate-dither3d) (2025).\n\n### License\n\nEverything I wrote myself is Unlicense / Public Domain. However some 3rd party libraries are used too:\n- Scanline rasterizer is based on Chris Hecker's [\"Perspective Texture Mapping\" series](https://chrishecker.com/Miscellaneous_Technical_Articles) (1995-1996),\n  specifically `SUBAFXFL.CPP`.\n- Modified version of Cameron Hart's [radixsort](https://github.com/bitshifter/radixsort), zlib license.\n- Mesh adjacency calculation based on Arseny Kapoulkine's [meshoptimizer](https://github.com/zeux/meshoptimizer), MIT license.\n- Parts were based on `mini3d` from Playdate SDK examples (Created by Dave Hayden on 10/20/15, Copyright © 2015 Panic, Inc.)\n  and on [mini3d-plus](https://github.com/nstbayless/mini3d-plus) (MIT license), but by now I have replaced them.\n- (only on PC): [stb_image.h](https://github.com/nothings/stb): Public Domain / MIT.\n- (only on PC): [Sokol](https://github.com/floooh/sokol): sokol_app, sokol_audio, sokol_gfx, sokol_time. zlib/libpng license.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Faras-p%2Fplaydators","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Faras-p%2Fplaydators","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Faras-p%2Fplaydators/lists"}