Playdate Mode7 Lua API

Playdate Mode7 is a library designed to recreate the graphics mode known as "Mode 7".

⚙️ Setup

Locate the pre-compiled binaries for your platform in the platforms/[platform] folder and copy the files (elf, dylib, dll) into the Source folder of the project.

Then import the Lua library:

import "mode7"

🌎 World

World is the root object of the library, it manages displays and sprites.

Luamode7.world.new(configuration)#
CPDMode7_World* mode7->world->newWorld(PDMode7_WorldConfiguration configuration);#

Creates a new world with the given configuration. By default, a world has a main display and a main camera.

Luamode7.world.defaultConfiguration() mode7.world.configuration#
CPDMode7_WorldConfiguration mode7->world->defaultConfiguration();#

Returns a new default configuration for the world.

Luamode7.world:getSize() width, height, depth#
CPDMode7_Vec3 mode7->world->getSize(PDMode7_World *world);#

Returns the world size.

Returned values are width and height of the 2D plane, depth is the third dimension.

Luamode7.world:getMainDisplay() mode7.display#
CPDMode7_Display* mode7->world->getMainDisplay(PDMode7_World *world);#

Returns the main display managed by the world.

By default, the main display has a camera already set.

Luamode7.world:setPlaneBitmap(bitmap)#
CPDMode7_Display* mode7->world->setPlaneBitmap(PDMode7_World *world, PDMode7_Bitmap *bitmap);#

Sets a bitmap for the plane.

The bitmap is a grayscale image loaded with bitmap.loadPGM(path).

Luamode7.world:getPlaneBitmap() mode7.bitmap#
CPDMode7_Bitmap* mode7->world->getPlaneBitmap(PDMode7_World *world);#

Returns the plane bitmap.

Luamode7.world:setPlaneFillColor(color)#
Cvoid mode7->world->setPlaneFillColor(PDMode7_World *world, PDMode7_Color color);#

Sets the plane color to be used for the out-of-bounds space.

Create the color with mode7.color.grayscale.new(gray, alpha)

Luamode7.world:getPlaneFillColor() mode7.color#
CPDMode7_Color mode7->world->getPlaneFillColor(PDMode7_World *world);#

Returns the plane color to be used for the out-of-bounds space.

Luamode7.world:worldToDisplayPoint(x, y, z, [display]) displayX, displayY, displayZ#
CPDMode7_Vec3 mode7->world->worldToDisplayPoint(PDMode7_World *world, PDMode7_Vec3 point, PDMode7_Display *display);#

Converts a world point to a display point. The z component of the returned value is 1 if the point is in front of the camera or -1 if the point is behind the camera.

Luamode7.world:displayToPlanePoint(displayX, displayY, [display]) planeX, planeY, planeZ#
CPDMode7_Vec3 mode7->world->displayToPlanePoint(PDMode7_World *world, int displayX, int displayY, PDMode7_Display *display);#

Converts a display point to a plane point. The z component of the returned value is 0 if the display point is on the plane, -1 if the display point is not on the plane.

Luamode7.world:displayMultiplierForScanlineAt(x, y, z, [display]) multiplierX, multiplierY, multiplierZ#
CPDMode7_Vec3 mode7->world->displayMultiplierForScanlineAt(PDMode7_World *world, PDMode7_Vec3 point, PDMode7_Display *display);#

Returns a multiplier that can be used to convert a length on a scanline, from the world coordinate system to the display coordinate system. This function is used to calculate the size of a sprite on display.

The z component of the multiplier is 1 if the point is in front of the camera or -1 if the point is behind the camera.

-- Calculate the width of a sprite on display
widthOnDisplay = spriteWidth * multiplierX
Luamode7.world:planeToBitmapPoint(planeX, planeY) bitmapX, bitmapY#
CPDMode7_Vec2 mode7->world->planeToBitmapPoint(PDMode7_World *world, float planeX, float planeY);#

Returns a bitmap point from a plane point. If the world scale is 1, the two points are equal.

The returned values are not rounded.

Luamode7.world:bitmapToPlanePoint(bitmapX, bitmapY) planeX, planeY#
CPDMode7_Vec2 mode7->world->bitmapToPlanePoint(PDMode7_World *world, float bitmapX, float bitmapY);#

Returns a bitmap point from a plane point. If the world scale is 1, the two points are equal.

Luamode7.world:addDisplay(display) boolean#
Cint mode7->world->addDisplay(PDMode7_World *world, PDMode7_Display *display);#

Adds the display to the world. It returns true if the display is added successfully, false if the maximum number of displays is reached or the display is already linked to a world.

Luamode7.world:addSprite(sprite)#
Cvoid mode7->world->addSprite(PDMode7_World *world, PDMode7_Sprite *sprite);#

Adds the sprite to the world.

Luamode7.world:update()#
Cvoid mode7->world->update(PDMode7_World *world);#

Updates the world state before drawing. This function calculates the visible sprites and their rects on screen.

Luamode7.world:draw([display])#
Cvoid mode7->world->draw(PDMode7_World *world, PDMode7_Display *display);#

Draws the contents of the world for the given display.

Luamode7.world:getSprites() mode7.array of mode7.sprite#
CPDMode7_Sprite** mode7->world->getSprites(PDMode7_World *world, int *length);#

Returns a mode7.array (not a Lua array) of all sprites added to the world.

Luamode7.world:getVisibleSpriteInstances([display]) mode7.array of mode7.sprite.instance#
CPDMode7_SpriteInstance** mode7->world->getVisibleSpriteInstances(PDMode7_World *world, int *length, PDMode7_Display *display);#

Returns a mode7.array (not a Lua array) of all visible sprite instances for the display.

You should call it after world:update.

⚙️ World Configuration

The configuration used to initialize the world.

Luamode7.world.configuration#
CPDMode7_WorldConfiguration#
{
   width=1024,
   height=1024,
   depth=1024,
   gridCellSize=256
}
Luamode7.world.configuration.width#
Cfloat width;#

Width of the 2D plane.

Luamode7.world.configuration.height#
Cfloat height;#

Height of the 2D plane.

Luamode7.world.configuration.depth#
Cfloat depth;#

Third dimension of the plane.

Luamode7.world.configuration.gridCellSize#
Cint gridCellSize;#

Size of the cell in the grid-based partitioning system. The grid is used to quickly determine visible sprites.

📺 Display

A Display draws the contents of a world on screen. You can add up to 4 displays to a world to get split screen or add a rear view camera in a racing game.

Luamode7.display.new(x, y, width, height)#
CPDMode7_Display* mode7->display->newDisplay(int x, int y, int width, int height);#

Creates a new display with the given rect.

Luamode7.display:setRect(x, y, width, height)#
Cvoid mode7->display->setRect(PDMode7_Display *display, int x, int y, int width, int height);#

Sets the rect of the display.

The x and width values must be multiple of 8.

Luamode7.display:getRect() x, y, width, height#
CPDMode7_Rect mode7->display->getRect(PDMode7_Display *display);#

Gets the rect of the display.

Luamode7.display:setOrientation(orientation)#
Cvoid mode7->display->setOrientation(PDMode7_Display *display, PDMode7_DisplayOrientation orientation);#

Sets the display orientation, default value is "landscape left".

You should set the display rect relative to the orientation. E.g. for a portrait display, the rect is x = 0, y = 0, width = 240, height = 400.

Functions such as world:worldToDisplayPoint return display coordinates relative to the orientation as well.

You can use display:convertPointFromOrientation to convert a point from the orientation coordinate system.

mode7.display.kOrientationLandscapeLeft
mode7.display.kOrientationLandscapeRight
mode7.display.kOrientationPortrait
mode7.display.kOrientationPortraitUpsideDown
Luamode7.display:getOrientation() mode7.display.kOrientation#
CPDMode7_DisplayOrientation mode7->display->getOrientation(PDMode7_Display *display);#

Gets the display orientation.

Luamode7.display:setCamera(camera)#
Cvoid mode7->display->setCamera(PDMode7_Display *display, PDMode7_Camera *camera);#

Sets the camera to the display.

Luamode7.display:getCamera() mode7.camera#
CPDMode7_Camera* mode7->display->getCamera(PDMode7_Display *display);#

Gets the camera of the display.

Luamode7.display:setScale(scale)#
Cvoid mode7->display->setScale(PDMode7_Display *display, PDMode7_DisplayScale scale);#

Sets the scale factor for the plane. It changes the plane resolution similarly to playdate.display.setScale(scale). You can change it to improve performance, default value is 2x2.

mode7.display.kScale1x1
mode7.display.kScale2x1
mode7.display.kScale2x2
mode7.display.kScale4x1
mode7.display.kScale4x2
Luamode7.display:getScale() mode7.display.kScale#
CPDMode7_DisplayScale mode7->display->getScale(PDMode7_Display *display);#

Gets the scale factor for the plane.

Luamode7.display:getBackground() mode7.display.background#
CPDMode7_Background* mode7->display->getBackground(PDMode7_Display *display);#

Returns the background interface associated to the display.

Luamode7.display:getHorizon()#
Cint mode7->display->getHorizon(PDMode7_Display *display);#

Returns the y position of the horizon, relative to the current display.

Luamode7.display:convertPointFromOrientation(x, y) x, y#
CPDMode7_Vec2 mode7->display->convertPointFromOrientation(PDMode7_Display *display, float x, float y);#

It converts a point from the orientation coordinate system, to the standard coordinate system. For a portrait orientation, the portrait point (0, 0) is converted to the standard point (400, 0).

Luamode7.display:convertPointToOrientation(x, y) x, y#
CPDMode7_Vec2 mode7->display->convertPointToOrientation(PDMode7_Display *display, float x, float y);#

It converts a point from the standard coordinate system, to the orientation coordinate system. For a portrait orientation, the standard point (0, 0) is converted to the portrait point (0, 400).

Luamode7.display:getWorld()#
CPDMode7_World* mode7->display->getWorld(PDMode7_Display *display);#

Returns the world associated to the display.

Luamode7.display:removeFromWorld()#
Cvoid mode7->display->removeFromWorld(PDMode7_Display *display);#

Removes the display from the world.

🌆 Background

Background is an interface that manages the world background.

Luamode7.display:getBackground() mode7.display.background#
CPDMode7_Background* mode7->display->getBackground(PDMode7_Display *display);#

Returns the background interface associated to the display.

Luamode7.background:setImage(image)#
CPDMode7_Background* mode7->background->setBitmap(PDMode7_Background *background, LCDBitmap *bitmap);#

Sets the background bitmap. You should use mode7.image.new(filename) to load it, you can't directly pass a Playdate image.

Luamode7.background:getImage() mode7.image#
CLCDBitmap* mode7->background->getBitmap(PDMode7_Background *background);#

Gets the background bitmap.

Luamode7.background:getOffset() x, y#
CPDMode7_Vec2 mode7->background->getOffset(PDMode7_Background *background);#

Gets the background offset.

Returned values are rounded according to the rounding increment.

Luamode7.background:setRoundingIncrement(x, y)#
Cvoid mode7->background->setRoundingIncrement(PDMode7_Background *background, unsigned int x, unsigned int y);#

Sets the rounding increment for the background. This value is used for rounding the position to the nearest integer. Default value is 1.

A value of 2 is usually good to prevent screen flashing.

Luamode7.background:getRoundingIncrement() x, y#
Cvoid mode7->background->getRoundingIncrement(PDMode7_Background *background, unsigned int *x, unsigned int *y);#

Gets the rounding increment for the background.

Luamode7.background:setCenter(cx, cy)#
Cvoid mode7->background->setCenter(PDMode7_Background *background, float x, float y);#

Sets the background center (0.0 - 1.0). Default value is (0.5, 0.5) so that the background is centered when the camera angle is 0.

Luamode7.background:getCenter() cx, cy#
CPDMode7_Vec2 mode7->background->getCenter(PDMode7_Background *background);#

Gets the background center.

🖼️ Bitmap

Bitmap is a grayscale image.

Luamode7.bitmap.loadPGM(path) mode7.bitmap#
CPDMode7_Bitmap* mode7->bitmap->loadPGM(const char *filename);#

Loads a PGM file at the given path, it returns NULL if the file can't be opened.

PGM is a grayscale image format, you can encode it with ImageMagick (recommended):

magick input.png -fx '(r+g+b)/3' -colorspace gray output.pgm

Bitmap data is stored in the pool.

Luamode7.bitmap:getSize() width, height#
Cvoid mode7->bitmap->getSize(PDMode7_Bitmap *bitmap, int *width, int *height);#

Gets the bitmap size.

Luamode7.bitmap:colorAt(x, y) mode7.color#
CPDMode7_Color mode7->bitmap->colorAt(PDMode7_Bitmap *bitmap, int x, int y);#

Gets the color value at the given position.

Luamode7.bitmap:setMask(mask)#
Cvoid mode7->bitmap->setMask(PDMode7_Bitmap *bitmap, PDMode7_Bitmap *mask);#

Sets a mask for the bitmap (transparent pixels are black). The mask size must be equal to the bitmap size.

You can create a mask with ImageMagick:

magick input.png -alpha extract mask.pgm

Mask is not supported for the plane bitmap.

Luamode7.bitmap:getMask() mode7.bitmap#
CPDMode7_Bitmap* mode7->bitmap->getMask(PDMode7_Bitmap *bitmap);#

Gets the bitmap mask.

Luamode7.bitmap:addLayer(layer)#
Cvoid mode7->bitmap->addLayer(PDMode7_Bitmap *bitmap, PDMode7_BitmapLayer *layer);#

Adds a layer to the bitmap.

Luamode7.bitmap:getLayers() mode7.array of mode7.bitmap.layer#
CPDMode7_BitmapLayer** mode7->bitmap->getLayers(PDMode7_Bitmap *bitmap, int *length);#

Returns a mode7.array (not a Lua array) of all layers added to the bitmap.

Luamode7.bitmap:removeAllLayers()#
Cvoid mode7->bitmap->removeAllLayers(PDMode7_Bitmap *bitmap);#

Removes all the layers from the bitmap.

🖼️ Bitmap Layer

A layer for drawing on top of a bitmap.

Please note that layers can't overlap each other. Also, a bitmap doesn't support hierarchical layers.

Luamode7.bitmap.layer.new(bitmap)#
CPDMode7_BitmapLayer* mode7->bitmap->layer->newLayer(PDMode7_Bitmap *bitmap);#

Creates a new layer with the given bitmap.

Luamode7.bitmap.layer:setBitmap(bitmap)#
Cvoid mode7->bitmap->layer->setBitmap(PDMode7_BitmapLayer *layer, PDMode7_Bitmap *bitmap);#

Sets a bitmap for the layer.

Consider setting a bitmap with the same size as the current bitmap to reduce memory allocations.

Luamode7.bitmap.layer:getBitmap()#
CPDMode7_Bitmap* mode7->bitmap->layer->getBitmap(PDMode7_BitmapLayer *layer);#

Gets the bitmap of the layer.

Luamode7.bitmap.layer:setPosition(x, y)#
Cvoid mode7->bitmap->layer->setPosition(PDMode7_BitmapLayer *layer, int x, int y);#

Sets the left-top position of the layer.

Luamode7.bitmap.layer:getPosition() x, y#
Cvoid mode7->bitmap->layer->getPosition(PDMode7_BitmapLayer *layer, int *x, int *y);#

Gets the layer position.

Luamode7.bitmap.layer:setVisible(visible)#
Cvoid mode7->bitmap->layer->setVisible(PDMode7_BitmapLayer *layer, int flag);#

Sets the layer visibility.

Luamode7.bitmap.layer:isVisible()#
Cint mode7->bitmap->layer->isVisible(PDMode7_BitmapLayer *layer);#

Gets the layer visibility.

Luamode7.bitmap.layer:invalidate()#
Cvoid mode7->bitmap->layer->invalidate(PDMode7_BitmapLayer *layer);#

Invalidates the layer forcing a redraw. This function is needed only for special cases, such as setting a new mask for the bitmap.

Luamode7.bitmap.layer:removeFromBitmap()#
Cvoid mode7->bitmap->layer->removeFromBitmap(PDMode7_BitmapLayer *layer);#

Removes the layer from the bitmap.

🎱 Pool

The Pool allows to store data in pre-allocated memory.

Luamode7.pool.realloc(size)#
Cvoid mode7->pool->realloc(size_t size);#

Resize the pool to the given size in bytes. We recommend to call this function only once.

Luamode7.pool.clear()#
Cvoid mode7->pool->clear();#

Clear the pool. You should call it before loading a new bitmap.

🎥 Camera

A Camera is a point of view with its own position and rotation.

Luamode7.camera.new()#
CPDMode7_Camera* mode7->camera->newCamera();#

Creates a new camera.

Luamode7.camera:setPosition(x, y, z)#
Cvoid mode7->camera->setPosition(PDMode7_Camera *camera, float x, float y, float z);#

Sets the camera position.

Luamode7.camera:getPosition() x, y, z#
CPDMode7_Vec3 mode7->camera->getPosition(PDMode7_Camera *camera);#

Gets the camera position.

Luamode7.camera:setAngle(angle)#
Cvoid mode7->camera->setAngle(PDMode7_Camera *camera, float angle);#

Sets the camera yaw angle.

Luamode7.camera:getAngle()#
Cfloat mode7->camera->getAngle(PDMode7_Camera *camera);#

Gets the camera yaw angle.

Luamode7.camera:setPitch(angle)#
Cvoid mode7->camera->setPitch(PDMode7_Camera *camera, float pitch);#

Sets the camera pitch angle.

Luamode7.camera:getPitch()#
Cfloat mode7->camera->getPitch(PDMode7_Camera *camera);#

Gets the camera pitch angle.

Luamode7.camera:setFOV(angle)#
Cvoid mode7->camera->setFOV(PDMode7_Camera *camera, float fov);#

Sets the camera FOV angle.

Luamode7.camera:getFOV()#
Cfloat mode7->camera->getFOV(PDMode7_Camera *camera);#

Gets the camera FOV angle.

Luamode7.camera:setClipDistanceUnits(units)#
Cvoid mode7->camera->setClipDistanceUnits(PDMode7_Camera *camera, int units);#

Sets the camera clip distance (distance within sprites are visible) expressed as units of the grid. A value of 1 will mark the sorrounding cells by a movement of 1 unit in all directions.

Luamode7.camera:getClipDistanceUnits()#
Cint mode7->camera->getClipDistanceUnits(PDMode7_Camera *camera);#

Gets the camera clip distance units.

Luamode7.camera:lookAtPoint(x, y, z)#
Cvoid mode7->camera->lookAtPoint(PDMode7_Camera *camera, PDMode7_Vec3 point);#

Adjusts the camera orientation (angle, pitch) to look at the given point.

🌳 Sprite

A Sprite is a 2D scalable image that represents a 3D entity in the world.

Luamode7.sprite.new(width, height, depth)#
CPDMode7_Sprite* mode7->sprite->newSprite(float width, float height, float depth);#

Creates a new sprite with the given size. Width and height are 2D values on the plane, depth is the third dimension.

Luamode7.sprite:getInstance(display) mode7.sprite.instance#
CPDMode7_SpriteInstance* mode7->sprite->getInstance(PDMode7_Sprite *sprite, PDMode7_Display *display);#

Gets the sprite instance for the given display.

Luamode7.sprite:setPosition(position)#
Cvoid mode7->sprite->setPosition(PDMode7_Sprite *sprite, float x, float y, float z);#

Sets the sprite center at the given position.

Luamode7.sprite:getPosition(sprite) x, y, z#
CPDMode7_Vec3 mode7->sprite->getPosition(PDMode7_Sprite *sprite);#

Gets the sprite position.

Luamode7.sprite:setSize(width, height, depth)#
Cvoid mode7->sprite->setSize(PDMode7_Sprite *sprite, float width, float height, float depth);#

Sets the sprite size.

Luamode7.sprite:getSize() width, height, depth#
CPDMode7_Vec3 mode7->sprite->getSize(PDMode7_Sprite *sprite);#

Gets the sprite size.

Luamode7.sprite:setAngle(angle)#
Cvoid mode7->sprite->setAngle(PDMode7_Sprite *sprite, float angle);#

Sets the sprite yaw angle.

Luamode7.sprite:getAngle()#
Cfloat mode7->sprite->getAngle(PDMode7_Sprite *sprite);#

Gets the sprite yaw angle.

Luamode7.sprite:setPitch(pitch)#
Cvoid mode7->sprite->setPitch(PDMode7_Sprite *sprite, float pitch);#

Sets the sprite pitch angle.

Luamode7.sprite:getPitch()#
Cfloat mode7->sprite->getPitch(PDMode7_Sprite *sprite);#

Gets the sprite pitch angle.

Luamode7.sprite:setFrame(frame)#
Cvoid mode7->sprite->setFrame(PDMode7_Sprite *sprite, unsigned int frame);#

Sets the sprite frame index (all instances).

Luamode7.sprite:setVisible(visible)#
Cvoid mode7->sprite->setVisible(PDMode7_Sprite *sprite, int flag);#

Sets the sprite visibility for all the instances.

Luamode7.sprite:setImageCenter(cx, cy)#
Cvoid mode7->sprite->setImageCenter(PDMode7_Sprite *sprite, float cx, float cy);#

Sets the image center for all the instances.

Luamode7.sprite:setRoundingIncrement(x, y)#
Cvoid mode7->sprite->setRoundingIncrement(PDMode7_Sprite *sprite, unsigned int x, unsigned int y);#

Sets the sprite rounding increment for all the instances.

Luamode7.sprite:setAlignment(alignmentX, alignmentY)#
Cvoid mode7->sprite->setAlignment(PDMode7_Sprite *sprite, PDMode7_SpriteAlignment alignmentX, PDMode7_SpriteAlignment alignmentY);#

Sets the sprite alignment for all the instances.

Luamode7.sprite:setImageTable(imageTable)#
Cfloat mode7->sprite->setBimapTable(PDMode7_Sprite *sprite, LCDBitmapTable *bitmapTable);#

Sets the sprite image table for all the instances.

Luamode7.sprite:setBillboardSizeBehavior(behavior)#
Cvoid mode7->sprite->setBillboardSizeBehavior(PDMode7_Sprite *sprite, PDMode7_SpriteBillboardSizeBehavior behavior);#

Sets the billboard size behavior for all the instances.

Luamode7.sprite:setBillboardSize(width, height)#
Cvoid mode7->sprite->setBillboardSize(PDMode7_Sprite *sprite, float width, float height);#

Sets the billboard size for all the instances.

Luamode7.sprite:setDrawFunctionName(functionName)#
Cvoid mode7->sprite->setDrawFunction(PDMode7_Sprite *sprite, PDMode7_SpriteDrawCallbackFunction *function);#

Sets a custom draw function for all the instances.

Luamode7.sprite:getDataSource()#

Gets the sprite data source interface.

Luamode7.sprite.datasource:setMaximumWidth(width)#
Cvoid mode7->sprite->datasource->setMaximumWidth(PDMode7_Sprite *sprite, int width);#

Sets the maximum width for the data source (all instances).

Luamode7.sprite.datasource:setMinimumWidth(width)#
Cvoid mode7->sprite->datasource->setMinimumWidth(PDMode7_Sprite *sprite, int width);#

Sets the minimum width for the data source (all instances).

Luamode7.sprite.datasource:setLengthForKey(length, key)#
Cvoid mode7->sprite->datasource->setLengthForKey(PDMode7_Sprite *sprite, unsigned int length, PDMode7_SpriteDataSourceKey key);#

Sets the length for the given data source key (all instances).

Luamode7.sprite.datasource:setLayout(k1, k2, k3, k4)#
Cvoid mode7->sprite->datasource->setLayout(PDMode7_Sprite *sprite, PDMode7_SpriteDataSourceKey k1, PDMode7_SpriteDataSourceKey k2, PDMode7_SpriteDataSourceKey k3, PDMode7_SpriteDataSourceKey k4);#

Sets the layout for the data source (all instances).

Luamode7.sprite:getWorld()#
CPDMode7_World* mode7->sprite->getWorld(PDMode7_Display *display);#

Returns the world associated to the sprite.

Luamode7.sprite:removeFromWorld()#
Cvoid mode7->sprite->removeFromWorld(PDMode7_Sprite *sprite);#

Removes the sprite from the world.

👥 Sprite Instance

A Sprite Instance allows to configure a sprite for a specific display.

Luamode7.sprite:getInstance(display) mode7.sprite.instance#
CPDMode7_SpriteInstance* mode7->sprite->getInstance(PDMode7_Sprite *sprite, PDMode7_Display *display);#

Gets the sprite instance for the given display.

Luamode7.sprite.instance:getSprite() mode7.sprite#
CPDMode7_Sprite* mode7->spriteInstance->getSprite(PDMode7_Sprite *sprite);#

Returns the sprite associated to the instance.

Luamode7.sprite.instance:setVisible(visible)#
Cvoid mode7->spriteInstance->setVisible(PDMode7_SpriteInstance *instance, int flag);#

Sets the visibility for the instance.

Luamode7.sprite.instance:isVisible()#
Cint mode7->spriteInstance->isVisible(PDMode7_SpriteInstance *instance);#

Gets the visibility for the instance.

Luamode7.sprite.instance:setFrame(frame)#
Cvoid mode7->spriteInstance->setFrame(PDMode7_SpriteInstance *instance, unsigned int frame);#

Sets the sprite frame index for the instance. If you want to animate your sprite, use this property to set the animation frame (starting from 0).

Animation length must be set in the data source by calling sprite.instance.datasource:setLengthForKey with the mode7.sprite.datasource.kFrame key.

Luamode7.sprite.instance:getFrame()#
Cunsigned int mode7->spriteInstance->getFrame(PDMode7_SpriteInstance *instance);#

Gets the sprite frame index for the instance.

Luamode7.sprite.instance:setImageCenter(cx, cy)#
Cvoid mode7->spriteInstance->setImageCenter(PDMode7_SpriteInstance *instance, float cx, float cy);#

Sets the image center (0.0 - 1.0) for the instance. Use this property to adjust the sprite position on screen, default value is (0.5, 0.5).

Luamode7.sprite.instance:getImageCenter() cx, cy#
CPDMode7_Vec2 mode7->spriteInstance->getImageCenter(PDMode7_SpriteInstance *instance);#

Gets the image center for the instance.

Luamode7.sprite.instance:setRoundingIncrement(x, y)#
Cvoid mode7->spriteInstance->setRoundingIncrement(PDMode7_SpriteInstance *instance, unsigned int x, unsigned int y);#

Sets the sprite rounding increment for the instance. This value is used for rounding the position on screen to the nearest integer. Default value is 1.

Luamode7.sprite.instance:getRoundingIncrement() x, y#
Cvoid mode7->spriteInstance->getRoundingIncrement(PDMode7_SpriteInstance *instance, unsigned int *x, unsigned int *y);#

Gets the sprite rounding increment for the instance.

Luamode7.sprite.instance:setAlignment(alignmentX, alignmentY)#
Cvoid mode7->spriteInstance->setAlignment(PDMode7_SpriteInstance *instance, PDMode7_SpriteAlignment alignmentX, PDMode7_SpriteAlignment alignmentY);#

Sets the sprite alignment for the instance. It aligns the sprite position on screen to even or odd values.

mode7.sprite.kAlignmentNone
mode7.sprite.kAlignmentEven
mode7.sprite.kAlignmentOdd
Luamode7.sprite.instance:getAlignment() alignmentX, alignmentY#
Cvoid mode7->spriteInstance->getAlignment(PDMode7_SpriteInstance *instance, PDMode7_SpriteAlignment *alignmentX, PDMode7_SpriteAlignment *alignmentY);#

Gets the sprite alignment for the instance.

Luamode7.sprite.instance:setImageTable(imageTable)#
Cvoid mode7->spriteInstance->setBitmapTable(PDMode7_SpriteInstance *instance, LCDBitmapTable *bitmapTable);#

Sets the image table for the instance. You should use mode7.imagetable.new to load it, you can't directly pass a Playdate image table.

You can set this property at any time (e.g. changing a character's image from idle to run). You can pass nil if you want to use a custom draw function sprite.instance:setDrawFunctionName

Luamode7.sprite.instance:getImageTable() mode7.imagetable#
CLCDBitmapTable* mode7->spriteInstance->getBitmapTable(PDMode7_SpriteInstance *instance);#

Gets the image table for the instance.

Luamode7.sprite.instance:setDrawFunctionName(functionName)#
Cvoid mode7->spriteInstance->setDrawFunction(PDMode7_SpriteInstance *instance, PDMode7_SpriteDrawCallbackFunction *function);#

Sets a custom draw function for the instance, you should pass the function name as a string (passing a table path with dots is not recommended).

To draw the sprite, call the provided callback drawSprite with instance as the first parameter.

function drawFunction(instance, x, y, w, h, drawSprite)
   drawSprite(instance)
end

instance:setDrawFunctionName("drawFunction")
Luamode7.sprite.instance:setBillboardSizeBehavior(behavior)#
Cvoid mode7->spriteInstance->setBillboardSizeBehavior(PDMode7_SpriteInstance *spriteInstance, PDMode7_SpriteBillboardSizeBehavior behavior);#

Sets the behavior for determining the billboard size.

  • When the behavior is set to automatic, the billboard width is determined by the longer side of the sprite.

  • When the behavior is set to custom, the billboard width is determined by the custom width.

Typically, only the billboard width is used to calculate the sprite rect on screen. The billboard height serves as a fallback value when the image is unavailable.

mode7.sprite.kBillboardSizeAutomatic
mode7.sprite.kBillboardSizeCustom
Luamode7.sprite.instance:setBillboardSize(width, height)#
Cvoid mode7->spriteInstance->setBillboardSize(PDMode7_SpriteInstance *spriteInstance, float width, float height);#

Sets a custom size for the billboard. The size is expressed in the world coordinate system. In order to use this property, set the behavior to custom.

Luamode7.sprite.instance:getBillboardSizeBehavior()#
CPDMode7_SpriteBillboardSizeBehavior mode7->spriteInstance->getBillboardSizeBehavior(PDMode7_SpriteInstance *instance);#

Gets the billboard size behavior.

Luamode7.sprite.instance:getBillboardSize()#
CPDMode7_Vec2 mode7->spriteInstance->getBillboardSize(PDMode7_SpriteInstance *instance);#

Gets the billboard custom size.

Luamode7.sprite.instance:getImage() playdate.graphics.image#

It returns the visible image for the instance.

The property is up-to-date for visible instances only. Ensure the instance is visible and call it after world:update

Luamode7.sprite.instance:getDisplayRect() x, y, width, height#
CPDMode7_Rect mode7->spriteInstance->getDisplayRect(PDMode7_SpriteInstance *instance);#

It returns the display rect for the instance.

The property is up-to-date for visible instances only. Ensure the instance is visible and call it after world:update

Luamode7.sprite.instance:isVisibleOnDisplay()#
Cint mode7->spriteInstance->isVisibleOnDisplay(PDMode7_SpriteInstance *instance);#

It returns true if the instance is visible on the associated display.

The property is up-to-date for visible instances only. Ensure the instance is visible and call it after world:update

⚙️ Sprite Data Source

The Sprite Data Source is an interface that describes how to retrieve an image from the image table.

Luamode7.sprite.instance:getDataSource() sprite.instance.datasource#
CPDMode7_SpriteDataSource* mode7->spriteInstance->getDataSource(PDMode7_SpriteInstance *instance);#

Returns the data source of the instance.

Luamode7.sprite.instance.datasource:setMaximumWidth(width)#
Cvoid mode7->spriteInstance->dataSource->setMaximumWidth(PDMode7_SpriteDataSource *dataSource, int maximumWidth);#

Sets the maximum width for the data source. This is the maximum width supported by the image table.

Pass 0 if you don't want to define a maximum width (sprite will always be drawn).

Luamode7.sprite.instance.datasource:getMaximumWidth()#
Cint mode7->spriteInstance->dataSource->getMaximumWidth(PDMode7_SpriteDataSource *dataSource);#

Gets the maximum width for the data source.

Luamode7.sprite.instance.datasource:setMinimumWidth(width)#
Cvoid mode7->spriteInstance->dataSource->setMinimumWidth(PDMode7_SpriteDataSource *dataSource, int minimumWidth);#

Sets the minimum width for the data source. This is the minimum width supported by the image table.

Luamode7.sprite.instance.datasource:getMinimumWidth()#
Cint mode7->spriteInstance->dataSource->getMinimumWidth(PDMode7_SpriteDataSource *dataSource);#

Gets the minimum width for the data source.

Luamode7.sprite.instance.datasource:setLengthForKey(length, key)#
Cvoid mode7->spriteInstance->dataSource->setLengthForKey(PDMode7_SpriteDataSource *dataSource, unsigned int length, PDMode7_SpriteDataSourceKey key);#

Sets the length for the given data source key. The default length for each key is 1 (length must be greater than 0).

Use this function to specify how many times a sprite is scaled and rotated in the image table.

E.g. For a rotation by 10 degrees, set a length of 36. For a scaling from 100px to 10px, set a length of 10.

mode7.sprite.datasource.kFrame
mode7.sprite.datasource.kAngle
mode7.sprite.datasource.kPitch
mode7.sprite.datasource.kScale
Luamode7.sprite.instance.datasource:setLayout(k1, k2, k3, k4)#
Cvoid PDMode7_SpriteDataSource* mode7->spriteInstance->dataSource->setLayout(PDMode7_SpriteDataSource *dataSource, PDMode7_SpriteDataSourceKey k1, PDMode7_SpriteDataSourceKey k2, PDMode7_SpriteDataSourceKey k3, PDMode7_SpriteDataSourceKey k4);#

Sets the layout for the data source. It defines the order of the image table, the default value "frame, angle, pitch, scale" implies the following structure:

begin frame-1
   begin angle-1
       begin pitch-1
           save [scale-1, scale-2, scale-3, ...]
       end pitch-1
       begin pitch-2
           save [scale-1, scale-2, scale-3, ...]
       end pitch-2
       ...
   end angle-1
   ...
end frame-1
...

A sprite is: rotated clockwise starting from the frontal position (for a character sprite, angle-1 will show the character's face), rotated in the positive pitch direction (for a character sprite, the head will move towards you), scaled from maximum to minimum width.

Notes:

  • An image is never repeated twice in the table.

  • Keys with a length of 1 are considered optional. For example, you can have a sprite with a single frame, angle, pitch but multiple scales.

  • Layout is not valid if you use the same key twice.

Luamode7.sprite.instance.datasource:getLengthForKey(key)#
Cunsigned int mode7->spriteInstance->dataSource->getLengthForKey(PDMode7_SpriteDataSource *dataSource, PDMode7_SpriteDataSourceKey key);#

Gets the length for the given data source key.

Luamode7.sprite.instance.datasource:getLayout() k1, k2, k3, k4#
Cvoid mode7->spriteInstance->dataSource->getLayout(PDMode7_SpriteDataSource *dataSource, PDMode7_SpriteDataSourceKey *k1, PDMode7_SpriteDataSourceKey *k2, PDMode7_SpriteDataSourceKey *k3, PDMode7_SpriteDataSourceKey *k4);#

Gets the layout for the data source.

🧱 Primitives

The library includes some primitives.

Luamode7.image.new(path) mode7.image#

Loads the image at the given path. Equivalent to playdate.graphics.image.new(path). Returns nil if the image can't be opened.

Luamode7.image:getPDImage() playdate.graphics.image#

Returns the underlying Playdate image.

Luamode7.imagetable.new(path) mode7.imagetable#

Loads the image table at the given path. Equivalent to playdate.graphics.imagetable.new(path). Returns nil if the image table can't be opened.

Luamode7.array:size() integer#

Gets the number of items in the array.

Luamode7.array:get(index) item#

Gets the item at the given index, array starts at index 1.

Luamode7.color.grayscale.new(gray, alpha) mode7.color#
CPDMode7_Color mode7->color->newGrayscaleColor(uint8_t gray, uint8_t alpha);#

Creates a new grayscale color.

🏎️ Performance tips

Here are some tips to improve the performance of your game:

  • Set an appropriate display scale (1x1 is the slowest, while 4x2 is the fastest).

  • Reduce the bitmap resolution to minimize cache misses.

  • Change the display scale or bitmap dynamically. When the camera is far from the plane, consider adjusting the display scale or swapping out the plane bitmap with a lower resolution version.

⚙️ Blender

You can use Blender to automatically generate a sprite image table. A Blender project is included in the blender folder of the library.

On macOS you need to launch Blender from the command line:

cd /Applications/Blender.app/Contents/MacOS
./Blender
  • Install Blender 4.0+

  • Install ImageMagick

  • Open the project in Blender and switch to the Scripting tab

  • Run the script

  • The image table will be saved in blender/output

⚙️ Tools

You can find a Python script to resize images (e.g. trees) in the tools/resize folder of the library. ImageMagick is required.

The resize.py script allows you to specify an image or a folder as input (-i), a maximum width (-max), a minimum width (-min), a step value (-step). Run "resize.py -h" for more info.

⚙️ Lua autocomplete

Copy the lua/stub.lua file into your VSCode workspace to support autocomplete and inline documentation.

This file contains placeholder code, you should not place it into the Source folder of the game.