Jet
Jet draait volledig in software met gebruik van snelle, integer-only rekenkunde. Het maakt uitsluitend gebruik van 16-bit RGB565-kleuren voor een snelle output naar 565-displays, zoals de ST7796, ILI9488 en andere vergelijkbare SPI-displays.
Op een ESP32 S3 is Jet in staat om ongeveer 40.000 driehoeken per seconde te renderen (flat shaded), of iets meer dan 650 on-screen driehoeken (na culling) bij 60fps op een resolutie van 480x320, of 1300 bij 30fps. In termen van prestaties bij deze resolutie bevindt dit zich ergens tussen de Sega 32X en de Sega Saturn.
Waar is Jet geschikt voor?
Jet heeft een specifieke focus. De ideale toepassingen zijn:
- Gestileerde / retro 3D: Flat-shaded, Gouraud-shaded of affine-textured geometrie, RGB565 framebuffers en de look van console- of arcade-3D uit het eind van de jaren 90.
- Hard real-time met een vast budget: Elke functie is een compile-time switch in
JetConfig.hpp, waardoor je alleen betaalt (in flash, RAM en CPU) voor wat je daadwerkelijk gebruikt. Als je Z-buffering, perspective-correct texturing of per-pixel lighting uitschakelt, wordt de bijbehorende code simpelweg niet gecompileerd. - Minimale geheugenvoetafdruk: Fixed-point rekenkunde in het kritieke pad, een optionele half-width framebuffer-modus, optionele interlaced field-buffer-modus voor 60 Hz op hardware die geen volledige progressieve frames aankan, en een optionele checkerboard-reconstructiemodus voor desktop.
- Voorspelbaar gedrag: Geen allocaties in het kritieke pad, geen virtuele dispatch in de rasterizer en geen verborgen globals. Dezelfde scène rendert op elk platform op dezelfde manier.
Jet is niet bedoeld voor PBR, real-time global illumination, mesh shaders of 4K. Als je echter een vloeiende, verlichte en getextureerde 3D-scène wilt plaatsen op een 320×240 LCD-scherm gekoppeld aan een microcontroller, of een low-poly software-rasterized esthetiek met hoge framerates op een desktop wilt renderen, dan is Jet precies daarvoor gebouwd.
Belangrijkste functies
De meeste functies kunnen individueel worden in- of uitgeschakeld via JetConfig.hpp (zie src/JetConfig.example.hpp voor de volledige lijst en documentatie).
Rendering
- Driehoeks- en quad-meshes met per-face materiaaltoewijzing.
- Flat, Gouraud, Phong en wireframe shading-modi (per materiaal).
- Affine en perspective-correct texture mapping; optionele bilinear filtering.
- RGB565-kleur over de hele linie (16-bit framebuffer, native voor de meeste embedded displays).
- Optionele Z-buffering, of painter's-algorithm sorting (per object en/of per driehoek) wanneer het geheugen beperkter is dan de CPU.
- Backface / frontface culling, depth bias voor decals/schaduwen, per-object blend-modi (replace, add, subtract, multiply, average, XOR).
- Screen-door alpha en noise-based dithering voor goedkope transparantie.
- Per-object afstand-gebaseerde fade-in / fade-out (ter vermindering van LOD pop) en scene-wide depth fog.
- Interlaced of Checkerboard rendering (met optionele reconstructie).
WATER_REFLECTshading-modus: een geanimeerd wateroppervlak in screen-space. Dit reflecteert de achtergrond-sky gradient rond een camera-pitch-correcte waterlijn, met per-materiaal ripple amplitude (specular) en verticale bias (waterYBias). Menging naar een vlakke tint gebeurt viamaterial->alpha.ADDITIVEshading-modus: saturating-add blend (src × alpha + dst). Volledig emissief; bedoeld voor neonreclames, lamp-coronas, explosie-halo's en gesimuleerde dynamische lichten.SSRFIELDREFLECT: wanneerFIELDBUFFERSactief is, sampletWATERREFLECTmirror-pixels uit de vorige committed field buffer, zodat reflecties nooit afhankelijk zijn van de depth-order en geen render-order artefacten vertonen over parallelle rendering-banden.- Perspective-correct Phong normal interpolatie (vult het bestaande perspective-correct UV-pad aan).
Verlichting
- Ambient- en directionele lichten met FLAT / GOURAUD / PHONG shading.
- Optionele
Z_BRIGHTNESS: goedkope depth darkening voor engines zonder een echt licht-rig.
Post-FX
- "Gratis" effecten (geen extra buffer): CRT scanlines, cell-shading.
- Buffered effecten (voor targets met veel RAM): FXAA, bloom, motion blur, chromatische aberratie, pixelatie.
Tooling
Primitives::create*helpers voor kubus / sfeer / cilinder / capsule / piramide / grid / vlak / quad / billboard.- Minimale Wavefront .obj loader.
- Optionele screen-space picking (compile-time begrensd; nul kosten wanneer ingesteld op 0). Geeft het dichtstbijzijnde geraakte object, driehoeksindex, diepte en gesnapte pixelcoördinaat terug.
- Geanimeerde palet-texturen:
Texture::advancePalette(dt, fps)cyclisch verschuift de palet-offset metdt × fpsentries per aanroep; geen actie wanneerpaletteSize0 is. - Een klein custom shader entry point voor gevallen waarin je buiten het fixed-function pad moet treden.
2D Sprites
Sprite2D is een lichtgewicht gecomponeerde 2D-sprite die over de scène wordt getekend na render(). Ondersteunt textured of solid-colour fills, colour-key transparantie, optionele alpha blend, additive blend, integer upscaling en zOrder-gebaseerde tekenvolgorde. Bij HALFWIDTHBUFFERS builds worden sprites op volledige output-resolutie gecomponeerd tijdens de display scanout.
Particles
ParticleSystem is een fixed-pool (geen heap) particle-systeem dat direct via de rasterizer wordt gerenderd na scene->render(). Wordt geleverd met een spark-emitter (impact-vonken met white → blue lifecycle) en een water-splash-emitter (kortstondige foam-to-blue spray). Distance LOD culls particles die te ver van de camera staan; het aantal emitters en de levensduur zijn instelbaar.
Lens flare
LensFlare is een n-element sprite-keten die een directionele lichtbron naar screen-space projecteert. Het kan optioneel een pick-slot bevragen voor sun occlusion testing en repositioneert flare-elementen langs de as van de zon naar het schermcentrum per frame. Fade-snelheid, per-element as-offset (axisT), basis-alpha, blend-modus en integer-schaal zijn allemaal configureerbaar. Werkt ook zonder picking (MAXPICKQUERIES = 0), in welk geval de zon als onbelemmerd wordt beschouwd.
Aan de slag
Jet is een library; het bezit geen window, display-driver of main loop. Voeg het toe als een CMake subdirectory of ESP-IDF component, zorg voor een JetConfig.hpp in je include-pad (kopieer en pas src/JetConfig.example.hpp aan), en roep vervolgens één keer per frame scene->render() aan.
Voor ESP-IDF voeg je het toe als een dependency in main/idf_component.yml:
dependencies:
jet: "*"
Zorg vervolgens dat er een JetConfig.hpp naast je applicatie staat.
Minimaal voorbeeld
Jet beheert zelf geen window, display-driver of main loop — het vult enkel een framebuffer die jij aanlevert. De onderstaande host-code is het kleinste bruikbare programma: het reserveert een kleur- en dieptebuffer, bouwt een scène met een camera, een lichtbron en een kubus, en roept vervolgens per frame scene->render() aan.
#include "Jet.hpp"
using namespace Renderer;
// 320x240 RGB565 kleur-buffer + bijbehorende Z-buffer.
constexpr int W = 320, H = 240;
uint16_t color[W * H];
uint16_t depth[ZBUFFER_STRIDE(W) * H];
int main() {
Scene scene(color, depth, W, H);
scene.setBackcolor(0x0000); // RGB565 clear kleur (zwart)
scene.setClearBuffer(true);
Camera camera;
camera.setPosition(0, 0, -500); // wereld-eenheden
camera.setFOV(75, W);
camera.nearPlane = 16;
camera.farPlane = 8192;
scene.setCamera(&camera);
DirectionalLight sun(Vector3{45, 35, 0}, Color{255, 245, 220}, 220);
AmbientLight amb(Color{40, 48, 64});
scene.setDirectionalLight(&sun);
scene.setAmbientLight(&amb);
Material red(0xF800); // RGB565: helder rood
red.shadingMode = ShadingMode::GOURAUD;
Object* cube = Primitives::createCube(200, 200, 200, &red);
cube->setPosition(0, 0, 200);
scene.addObject(cube);
// Per frame: roteer, render, push de buffer naar je display.
for (;;) {
cube->rotate(0, 1, 0); // 1 graad per frame rond Y
scene.render(); // kleur-buffer bevat nu het frame
// pushToDisplay(color, W, H); // <-- dit moet je zelf implementeren
}
}
Er is geen Jet-side main(), geen platform-glue en geen event pump. Alles wat communiceert met je display (SPI, parallel RGB, DMA, SDL streaming texture, fbdev, ...) moet door jou worden verzorgd; Jet stopt bij de framebuffer.
Documentatie
De volledige API-referentie is gegenereerd vanuit de inline Doxygen-commentaren in src/ en is gepubliceerd via GitHub Pages op: https://cubecoders.github.io/Jet/
Om de documentatie lokaal te bouwen (vereist doxygen en optioneel graphviz):
cd components/Jet/src
doxygen Doxyfile
# output: components/Jet/src/docs/html/index.html
De repository is zo geconfigureerd dat de Doxygen-output automatisch naar GitHub Pages wordt gepubliceerd bij elke push naar de default branch.
Licentiëring
Jet is dual-licensed.
1. Open-source: AGPL-3.0-or-later
Jet wordt gedistribueerd onder de GNU Affero General Public License versie 3, of (naar keuze) een latere versie. De volledige tekst staat in LICENSE. Je bent vrij om Jet te gebruiken, bestuderen, modificeren en redistribueren onder de voorwaarden van de AGPL. Kort gezegd: iedereen aan wie je een binary distribueert (inclusief gebruikers die ermee interacteren via een netwerk) heeft recht op de volledige corresponderende broncode van de applicatie die tegen Jet linkt, onder de AGPL. Dit is een bewuste keuze om Jet (en verbeteringen daaraan) gratis te houden voor iedereen.
Als je een hobbyist, academicus, open-source project of een bedrijf bent dat sowieso de broncode verspreidt, is deze licentie waarschijnlijk passend.
2. Commerciële licentie
Als je een closed-source product wilt leveren dat linkt tegen Jet — oftewel, als je de broncode van je applicatie niet onder de AGPL wilt vrijgeven — is er een commerciële licentie beschikbaar via CubeCoders. De commerciële licentie heft de verplichting tot broncode-openbaring van de AGPL voor jouw product op, terwijl de upstream Jet-code zelf ongewijzigd blijft.
Commerciële licenties: https://cubecoders.com/jet
De open-source licentie is bewust strikt gehouden (AGPL, niet LGPL of MIT), zodat de commerciële licentie betekenis heeft. Inkomsten uit commerciële licenties financieren de verdere ontwikkeling van de open-source versie.
Bijdragen
Bijdragen zijn welkom — bugrapporten, fixes, nieuwe platformen, nieuwe voorbeelden, documentatie-verbeteringen, etc. Open hiervoor een issue of pull request in de officiële repository.
Lees vóór je eerste bijdrage CONTRIBUTING.md. Omdat Jet dual-licensed is (AGPL + commercieel), moet elke contributor akkoord gaan met de Contributor Licence Agreement (CLA). Deze machtigt CubeCoders expliciet om bijdragen zowel onder de commerciële Jet-licentie als onder de upstream AGPL-versie te licentiëren.
Groetjes,