Implemented in src/lua/luaviewapi.cpp.
A view is a camera position, a viewport rectangle, a zoom and a scroll step.
The renderer owns one built-in view, the default view (id 0, from
renderer_get_default_view), and it is the one the older global camera_*,
zoom_* and viewport_* functions act on — those keep working unchanged. The
view_* functions here take the view first, so that when more views exist
(several views in one window: a minimap, picture-in-picture, split screen) the
same calls address any of them. view_create adds further views over the same world
(a minimap, a close-up, picture-in-picture, split screen), each with its own
rectangle, camera and zoom, and each drawn every frame.
View handles are opaque integers. Every function reports failure as
nil, "message" (never a Lua error) — an unknown view is
nil, "unknown view N".
Zoom is always a factor — a whole multiple of ZOOM_STEP (0.0625) between
ZOOM_FACTOR_MIN and ZOOM_FACTOR_MAX; 3.8125 is valid, 3.8 is rejected with
the nearest valid factor named. Changing a view's zoom or viewport does not move
its camera: the camera position is not re-clamped, so set it again afterwards
(view_set_camera_position).
What an extra view is for, and its limits. Every view shows the same map,
sprites and layers — there is one world seen through several windows. A view can
hide layers (view_show_layer, view_show_only_layers), be hidden
(view_set_visible), be drawn above or below another (view_set_draw_order) and
have its own backdrop (view_set_clear_background, view_set_background_color).
Each visible extra view costs one more full pass over the map per frame. What is
not per-view: collisions and input stay in the default view's space, and an
ordinary sprite's position is relative to the view it is drawn in — a sprite meant
to appear at the same map position in every view needs sprite_set_world_space.
Image layers are drawn only in the default view.
view_create(renderer, x, y, w, h) -> view | nil, messageCreate an additional view over the same world and return its handle (an integer
of at least 1; 0 is the default view). The rectangle [x, x + w) × [y, y + h)
is where in the render area the view is drawn: all four are integers, x/y at
least 0, w/h at least 1, and it must fit the render area
(x + w <= width, y + h <= height) — otherwise nil and the reason.
A new view starts visible, with its camera at the map's origin, zoom 1.0,
scroll step the map's tile size, every layer shown, an opaque backdrop in the
map's own background colour, and a draw order equal to its own id (so it is drawn
on top of the default view, and later views on top of earlier ones). Configure it
with the other view_* functions — for a minimap that is usually
view_fit_to_map( view ) once the map is loaded. Ids are never reused: a
destroyed view's id answers nil, "unknown view N" from then on.
Each visible extra view costs one more full pass over the map per frame.
local renderer = renderer_get_current()
local minimap, err = view_create( renderer, 1000, 20, 240, 240 )
assert( minimap, err )
view_fit_to_map( minimap ) -- once a map is loaded
view_destroy(view) -> true | nil, messageRemove a view: it is no longer drawn and no longer counted
(renderer_get_view_count). The default view can never be removed
(nil, "the default view cannot be removed"), and a view that was already
destroyed is nil, "unknown view N".
local ok, err = view_destroy( minimap )
view_set_zoom(view, factor) -> true | nil, message / view_get_zoom(view) -> factor | nil, messageSet (or read) a view's current zoom factor. The factor must be a whole
multiple of ZOOM_STEP (0.0625) within the view's zoom limits (by default
ZOOM_FACTOR_MIN to ZOOM_FACTOR_MAX); anything else returns nil and the reason,
naming the nearest valid factor. This sets only the current zoom —
view_zoom_reset still returns to the preferred zoom (view_set_preferred_zoom).
The camera is not moved.
local ok, err = view_set_zoom( view, 3.8125 )
assert( ok, err )
assert( view_get_zoom( view ) == 3.8125 )
view_set_preferred_zoom(view, factor) -> true | nil, message / view_get_preferred_zoom(view) -> factor | nil, messageSet (or read) the zoom view_zoom_reset returns to. Validated exactly like
view_set_zoom (a valid factor, within the view's zoom limits).
view_set_preferred_zoom( view, 1.0 )
view_zoom_reset( view ) -- back to 1.0
view_set_zoom_limits(view, min_factor, max_factor) -> true | nil, message / view_get_zoom_limits(view) -> min_factor, max_factor | nil, messageSet (or read) the lowest and highest zoom factor a view may be at (both
inclusive). Each must be a valid zoom factor and min_factor must not exceed
max_factor. Limits can be widened again as well as narrowed. Narrowing them
clamps the view's current and preferred zoom into the new range. view_get_zoom_limits
returns both.
view_set_zoom_limits( view, 1.0, 4.0 )
local lo, hi = view_get_zoom_limits( view ) -- 1.0, 4.0
view_set_zoom_enabled(view, enabled) -> true | nil, message / view_get_zoom_enabled(view) -> enabled | nil, messageEnable or disable a view's zoom stepping — view_zoom_in/view_zoom_out (and the
global zoom_in/zoom_out on the default view) do nothing while it is off.
Setting an exact zoom with view_set_zoom and view_zoom_reset still work.
view_get_zoom_enabled reads it back.
view_set_zoom_enabled( view, false ) -- lock the zoom against zoom_in/zoom_out
view_zoom_in(view) -> true | nil, messageStep a view's zoom in by one ZOOM_STEP (a no-op at the zoom limit, or while zoom
is disabled — see view_set_zoom_enabled).
view_zoom_in( view )
view_zoom_out(view) -> true | nil, messageStep a view's zoom out by one ZOOM_STEP (a no-op at the zoom limit, or while zoom
is disabled — see view_set_zoom_enabled).
view_zoom_out( view )
view_zoom_reset(view) -> true | nil, messageReturn a view's zoom to its preferred zoom (see view_set_preferred_zoom) — not
to whatever zoom the view was created with.
view_zoom_reset( view )
view_set_dimension(view, x, y, w, h) -> true | nil, message / view_get_dimension(view) -> x, y, w, h | nil, messageSet (or read) a view's viewport: the rectangle [x, x + w) × [y, y + h) of the
render area it is shown in — w and h are a real width and height. All four
must be integers, x/y at least 0, w/h at least 1, and the rectangle
must fit the render area (x + w <= width, y + h <= height, the width/height
the renderer was created with). The camera is not moved: set it again
(view_set_camera_position) if the new rectangle needs a different one.
view_get_dimension returns x, y, w, h.
local ok, err = view_set_dimension( view, 10, 10, 1240, 900 )
assert( ok, err )
view_set_scroll_step(view, w, h) -> true | nil, message / view_get_scroll_step(view) -> w, h | nil, messageSet (or read) how many pixels one view_move_camera_* call moves a view's camera:
w horizontally, h vertically, both integers of at least 1.
view_get_scroll_step returns w, h — the step the next move would use. It is
-1 only while no step was ever set and no map is loaded yet (the default is the
loaded map's tile size).
view_set_scroll_step( view, 4, 4 )
view_move_camera_down( view ) -- moves 4 pixels
view_set_camera_position(view, x, y) -> true | nil, message / view_get_camera_position(view) -> x, y | nil, messageJump a view's camera so the given world-space coordinate is shown at the top-left of
its viewport, and (with view_get_camera_position) read it back. Both integers.
Unlike the view_move_camera_* calls this does not clamp to the map, and it is
not re-clamped when the view's zoom or viewport changes — set it again afterwards.
view_set_camera_position( view, 0, 0 )
local x, y = view_get_camera_position( view )
Move a view's camera up by its scroll step, stopping at the map's edge (unlike
view_set_camera_position). Also view_move_camera_down, view_move_camera_left
and view_move_camera_right. Up and left need a loaded map (their limit is its
size): with none, they return nil, "no map is loaded...".
view_move_camera_up( view )
view_reset_camera(view) -> true | nil, messageReturn a view's camera to the origin of the map.
view_reset_camera( view )
view_set_visible(view, visible) -> true | nil, message / view_get_visible(view) -> visible | nil, messageShow or hide a view (and read it back with view_get_visible). A hidden view keeps
all its state — camera, zoom, layer mask — and is simply skipped by the frame; the
sprites on a layer that only hidden views show are not advanced either, exactly as
for a hidden layer. Every view is visible when created. Hiding the default view
hides the game's main picture, which is rarely what you want.
view_set_visible( minimap, false ) -- toggle the minimap off
view_set_draw_order(view, order) -> true | nil, message / view_get_draw_order(view) -> order | nil, messageSet the order views are drawn in (and read it back with view_get_draw_order):
ascending, so a view with a higher order is drawn later — on top of — one with a
lower order; views with the same order are drawn by ascending id. order is an
integer. The default view starts at 0 and a view made by view_create starts at
its own id, so by default extra views are on top of the default one, later ones on
top of earlier ones.
view_set_draw_order( closeup, 10 ) -- above every view with a lower order
view_set_clear_background(view, clear) -> true | nil, message / view_get_clear_background(view) -> clear | nil, messageChoose whether a view's rectangle is filled with its background colour before its
layers are drawn (and read it back with view_get_clear_background). It is on by
default. Turn it off for a transparent overlay; leave it on (with an opaque
colour, see view_set_background_color) so the scene underneath does not show
through, which is what a minimap normally wants. For the default view this is
the whole frame's background, cleared once before any view is drawn.
view_set_clear_background( hud, false ) -- draw the view over what is below it
view_set_background_color(view, r, g, b [, a]) -> true | nil, messageFill a view's backdrop with this colour instead of the map's own. Each of r, g,
b and the optional a (default 255, opaque) is an integer 0–255; an alpha
below 255 blends the backdrop over what is already drawn there. It only matters
while view_set_clear_background is on. There is no getter. For the default view
this overrides the whole frame's background colour.
view_set_background_color( minimap, 0, 0, 0, 160 ) -- translucent black
view_use_map_background_color(view) -> true | nil, messageGo back to the default backdrop colour after view_set_background_color: the
loaded map's own background colour, or the window's when no map is loaded.
view_use_map_background_color( minimap )
view_show_layer(view, layer, show) -> true | nil, messageShow or hide one layer in this view only (the layer itself, and what every
other view shows, are untouched). layer is the layer's integer id, or its name
as a string — a name needs a loaded map with a layer of that name, otherwise
nil and the reason; an id may be set before the map is loaded (the mask is kept
by id, and an id that names no layer is simply never matched). show is a
boolean. Every layer is shown by default.
A hidden layer's sprites are not drawn in this view either — sprites belong to their layer. A hidden group layer hides everything inside it whatever its children's own settings, so to show a child, its group must be shown too.
view_show_layer( minimap, "clouds", false )
view_show_layer( minimap, 3, true )
view_show_only_layers(view, layer_ids) -> true | nil, messageShow only the layers whose ids are in the table layer_ids (a list of
integers) in this view; every other layer — including any added to the map later —
is hidden in it. Remember that a hidden group hides its children, so list a
child's group as well. An empty table hides every layer. view_show_all_layers
undoes it.
view_show_only_layers( minimap, { 1, 2, 5 } )
view_show_all_layers(view) -> true | nil, messageClear the view's layer mask: every layer is shown again.
view_show_all_layers( minimap )
view_is_layer_shown(view, layer_id) -> shown | nil, messageWhether this view's layer mask shows the layer with this integer id. It reports
only what the mask says — a layer's own visible flag (tilemap_set_layer) is a
separate thing and applies to every view.
if not view_is_layer_shown( minimap, 3 ) then print( "layer 3 is masked out" ) end
view_fit_to_map(view) -> true | nil, messageZoom the view to the largest zoom at which the whole loaded map fits inside its
rectangle, and put its camera at the map's top-left — the usual setup for a
minimap. The zoom is clamped to the view's zoom limits, so a map too large to fit
even at the lowest zoom shows as much as that zoom allows. Nothing else about the
view changes. With no map loaded it returns nil, "no map is loaded".
assert( tilemap_load_map( map_path, MAP_ALIGNMENT_TOP_LEFT ) )
view_fit_to_map( minimap )