Playdate Mode7 is a library designed to recreate the graphics mode known as "Mode 7".
To get started, include the library:
#include "pd_mode7.h"
And initialize it:
PDMode7_init(pd, 0);
Initializes the library.
To add the Lua support, call this method in kEventInitLua and pass 1 as the second parameter.
World is the root object of the library, it manages displays and sprites.
Creates a new world with the given configuration. By default, a world has a main display and a main camera.
You should not free the display and camera managed by the world.
Returns a new default configuration for the world.
Returns the world size.
x and y are the width and height of the 2D plane, z is the third dimension.
Returns the main display managed by the world.
By default, the main display has a camera already set.
Returns the main camera managed by the world.
Sets a bitmap for the plane.
The bitmap is a grayscale image loaded with bitmap->loadPGM(filename).
Returns the plane bitmap.
Sets the plane color to be used for the out-of-bounds space.
Returns the plane color to be used for the out-of-bounds space.
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.
Display is optional, pass NULL for the main 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.
Display is optional, pass NULL for the main 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.
Display is optional, pass NULL for the main display.
// Calculate the width of a sprite on display float widthOnDisplay = spriteWidth * multiplier.x;
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.
Returns a bitmap point from a plane point. If the world scale is 1, the two points are equal.
Adds the display to the world. It returns 1 if the display is added successfully, 0 if the maximum number of displays is reached or the display is already linked to a world.
Adds the sprite to the world.
Updates the world state before drawing. This function calculates the visible sprites and their rects on screen.
Draws the contents of the world for the given display.
Display is optional, pass NULL for the main display.
Returns an array of all sprites added to the world.
You shouldn't free the returned pointer.
Returns an array of all visible sprite instances for the display.
You should call it after world->update. You shouldn't free the returned pointer.
Frees the given world.
The configuration used to initialize the world.
typedef enum { float width; float height; float depth; int gridCellSize; } PDMode7_WorldConfiguration;
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.
Creates a new display with the given rect.
Sets the rect of the display.
The x and width values must be multiple of 8.
Gets the rect of the display.
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.
typedef enum { kMode7DisplayOrientationLandscapeLeft, kMode7DisplayOrientationLandscapeRight, kMode7DisplayOrientationPortrait, kMode7DisplayOrientationPortraitUpsideDown, } PDMode7_DisplayOrientation;
Gets the display orientation.
Sets the camera to the display.
Gets the camera of the display.
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.
typedef enum { kMode7DisplayScale1x1, kMode7DisplayScale2x1, kMode7DisplayScale2x2, kMode7DisplayScale4x1, kMode7DisplayScale4x2 } PDMode7_DisplayScale;
Gets the scale factor for the plane.
Returns the background interface associated to the display.
Returns the y position of the horizon, relative to the current display.
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).
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).
Returns the world associated to the display.
Removes the display from the world.
Frees the given display.
Background is an interface that manages the world background.
Returns the background interface associated to the display.
Sets the background bitmap. You should use mode7.image.new(filename) to load it, you can't directly pass a Playdate image.
Gets the background bitmap.
Gets the background offset.
Returned values are rounded according to the rounding increment.
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.
Gets the rounding increment for the background.
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.
Bitmap is a grayscale image.
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.
Gets the bitmap size.
Gets the color value at the given position.
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.
Gets the bitmap mask.
Adds a layer to the bitmap.
Returns an array of all layers added to the bitmap.
You shouldn't free the returned pointer.
Removes all the layers from the bitmap.
Frees the given bitmap.
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.
Creates a new layer with the given bitmap.
Sets a bitmap for the layer.
Consider setting a bitmap with the same size as the current bitmap to reduce memory allocations.
Gets the bitmap of the layer.
Sets the left-top position of the layer.
Gets the layer position.
Sets the layer visibility.
Gets the layer visibility.
Invalidates the layer forcing a redraw. This function is needed only for special cases, such as setting a new mask for the bitmap.
Removes the layer from the bitmap.
Frees the given layer.
The Pool allows to store data in pre-allocated memory.
A Camera is a point of view with its own position and rotation.
Sets the camera position.
Gets the camera position.
Sets the camera yaw angle.
Gets the camera yaw angle.
Sets the camera pitch angle.
Gets the camera pitch angle.
Sets the camera FOV angle.
Gets the camera FOV angle.
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.
Gets the camera clip distance units.
Adjusts the camera orientation (angle, pitch) to look at the given point.
Frees the given camera.
A Sprite is a 2D scalable image that represents a 3D entity in the world.
Creates a new sprite with the given size. Width and height are 2D values on the plane, depth is the third dimension.
Gets the sprite instance for the given display.
Sets the sprite center at the given position.
Gets the sprite position.
Sets the sprite size.
Gets the sprite size.
Sets the sprite yaw angle.
Gets the sprite yaw angle.
Sets the sprite pitch angle.
Gets the sprite pitch angle.
Sets the sprite frame index (all instances).
See also spriteInstance->setFrame
Sets the sprite visibility for all the instances.
See also spriteInstance->setVisible
Sets the image center for all the instances.
See also spriteInstance->setImageCenter
Sets the sprite rounding increment for all the instances.
See also spriteInstance->setRoundingIncrement
Sets the sprite alignment for all the instances.
See also spriteInstance->setAlignment
Sets the sprite image table for all the instances.
See also spriteInstance->setBitmapTable
Sets the billboard size behavior for all the instances.
Sets the billboard size for all the instances.
See also spriteInstance->setBillboardSize
Sets a custom draw function for all the instances.
See also spriteInstance->setDrawFunction
Sets the custom userdata for all the instances.
Sets the maximum width for the data source (all instances).
Sets the minimum width for the data source (all instances).
Sets the length for the given data source key (all instances).
Sets the layout for the data source (all instances).
Returns the world associated to the sprite.
Removes the sprite from the world.
Frees the given sprite.
A Sprite Instance allows to configure a sprite for a specific display.
Gets the sprite instance for the given display.
Returns the sprite associated to the instance.
Sets the visibility for the instance.
Gets the visibility for the instance.
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 spriteInstance->dataSource->setLengthForKey with the kMode7SpriteDataSourceFrame key.
Gets the sprite frame index for the instance.
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).
Gets the image center for the instance.
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.
Gets the sprite rounding increment for the instance.
Sets the sprite alignment for the instance. It aligns the sprite position on screen to even or odd values.
typedef enum { kMode7SpriteAlignmentNone, kMode7SpriteAlignmentEven, kMode7SpriteAlignmentOdd, } PDMode7_SpriteAlignment;
Gets the sprite alignment for the instance.
Sets the bitmap table for the instance.
You can set this property at any time (e.g. changing a character's image from idle to run). You can pass NULL if you want to use a custom draw function spriteInstance->setDrawFunction
Sets the bitmap table for the instance.
Sets a custom draw function for the instance. To draw the sprite, call the provided callback drawSprite or use bitmap.
void drawFunction(PDMode7_SpriteInstance *instance, LCDBitmap *bitmap, PDMode7_Rect rect, void(*drawSprite)(PDMode7_SpriteInstance *instance)){ drawSprite(instance); }
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.
typedef enum { kMode7BillboardSizeAutomatic, kMode7BillboardSizeCustom } PDMode7_SpriteBillboardSizeBehavior;
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.
Gets the billboard size behavior.
Gets the billboard custom size.
It returns the visible bitmap for the instance.
The property is up-to-date for visible instances only. Ensure the instance is visible and call it after world->update
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
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
Sets the custom userdata for the instance.
Gets the custom userdata for the instance.
The Sprite Data Source is an interface that describes how to retrieve an image from the image table.
Returns the data source of the instance.
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).
Gets the maximum width for the data source.
Sets the minimum width for the data source. This is the minimum width supported by the image table.
Gets the minimum width for the data source.
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.
typedef enum { kMode7SpriteDataSourceFrame, kMode7SpriteDataSourceAngle, kMode7SpriteDataSourcePitch, kMode7SpriteDataSourceScale } PDMode7_SpriteDataSourceKey;
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.
Gets the length for the given data source key.
Gets the layout for the data source.
The library includes some primitives.
Creates a new 2D vector.
Creates a new 3D vector.
Creates a new rect (integer).
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.
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
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.