Build, entry point and the first working frame.

The startup slice of the public API: compilation requirements, build flags, begin3D(...), the minimal example and integration notes.

1. Compilation Requirements

Pip3D uses C++17.

For PlatformIO:

build_unflags =
    -std=gnu++11
build_flags =
    -std=gnu++17

2. Build-time Configuration

Main compile-time flags for Pip3D and the lower PipCore layer:

  • PIP3D_SCREEN_WIDTH
    • logical screen width
  • PIP3D_SCREEN_HEIGHT
    • logical screen height
  • PIP3D_SCREEN_BAND_COUNT
    • number of horizontal bands for banded rendering
  • PIPCORE_PLATFORM
    • PipCore platform
    • example: ESP32
  • PIPCORE_DISPLAY
    • display driver
    • example: ILI9488, ST7789
  • PIPCORE_ENABLE_PREFS
    • 0 or 1
  • PIPCORE_ENABLE_WIFI
    • 0 or 1
  • PIPCORE_ENABLE_OTA
    • 0 or 1
  • PIPCORE_OTA_PROJECT_URL
    • OTA backend URL when OTA is actually used

Example via platformio.ini:

build_flags =
    -std=gnu++17
    -Ilib/Pip3D
    -Ilib/Pip3D/Pip3D
    -Iinclude
    -DPIP3D_SCREEN_WIDTH=480
    -DPIP3D_SCREEN_HEIGHT=320
    -DPIP3D_SCREEN_BAND_COUNT=2
    -DPIPCORE_PLATFORM=ESP32
    -DPIPCORE_DISPLAY=ILI9488

You can also define the same values through include/config.hpp if that is a more convenient place for project-level config.

Important:

  • PIP3D_SCREEN_WIDTH and PIP3D_SCREEN_HEIGHT are engine-level compile-time constants, not cosmetic values
  • runtime begin3D(width, height, ...) must not contradict those macros
  • if your project uses a 480x320 screen, the compile-time flags must also be 480x320
  • PIP3D_SCREEN_BAND_COUNT=2 or higher lowers framebuffer/z-buffer memory usage, but makes the pipeline more complex
  • 2 is a sensible default for regular projects
  • optional PipCore modules are disabled by default, so external code should not call Wi-Fi / OTA API without explicitly enabling the flags

3. Include and Entry Point

Main include:

#include "Pip3D.h"
using namespace pip3D;

Main public entry points:

  • const char* getVersion()
  • Color RGB888(uint8_t r, uint8_t g, uint8_t b)
  • Renderer& renderer()
  • Renderer& begin3D(uint16_t width, uint16_t height, int8_t cs, int8_t dc, int8_t rst, int8_t bl = -1, uint32_t spi_freq = 80000000)
  • Renderer& begin3D(int8_t cs, int8_t dc, int8_t rst, int8_t bl = -1, uint32_t spi_freq = 80000000)

Example:

Renderer& r = begin3D(480, 320, 10, 9, 8, -1, 80000000);

What begin3D(...) does:

  • initializes the singleton renderer
  • sets up the display, framebuffer and z-buffer
  • enables SKYBOX_DAY
  • enables shadows
  • places the shadow plane at Y = 0

Important:

  • the overload begin3D(cs, dc, rst, ...) uses the default 320x240
  • if your project is not 320x240, use the overload with explicit width and height
  • renderer() returns the global Renderer singleton

16. Minimal Working Example

#include <Arduino.h>
#include "Pip3D.h"

using namespace pip3D;

Renderer* g_renderer = nullptr;
Cube* g_cube = nullptr;

void setup()
{
    g_renderer = &begin3D(480, 320, 10, 9, 8);

    Camera& cam = g_renderer->getCamera();
    cam.position = Vector3(0.0f, 2.0f, -6.0f);
    cam.lookAt(Vector3(0.0f, 0.5f, 5.0f));
    cam.setPerspective(60.0f, 0.1f, 100.0f);

    g_renderer->setSkyboxWithLighting(SKYBOX_DAY);
    g_renderer->setShadowPlaneY(0.0f);

    g_cube = new Cube(1.0f, Color::fromRGB888(220, 220, 230));
    g_cube->setPosition(0.0f, 0.5f, 5.0f);
}

void loop()
{
    float dt = getDeltaTime();
    g_cube->rotate(0.0f, 40.0f * dt, 0.0f);

    g_renderer->beginFrame();
    g_renderer->drawMesh(g_cube);
    g_renderer->drawText(8, 8, "Pip3D", Color::WHITE);
    g_renderer->endFrame();
}

17. Practical Notes

  • External code should usually start with begin3D(...), Renderer, Camera, Mesh and Light.
  • If you need many similar objects, use MeshInstance and InstanceManager instead of separate Mesh copies.
  • If you need a full object hierarchy, use SceneGraph and Node-derived types.
  • If you need a cutscene, use CameraTimeline.
  • If you need a day/night cycle, use TimeOfDayController.
  • If you need a simple test character, use CharacterController.
  • If you need a quick effect prototype, use FXSystem.
  • Internal renderer and pipeline headers should not be the main integration point for user code.