Textures¶
Mods should generally prefix their textures with modname_
, e.g. given
the mod name foomod
, a texture could be called:
foomod_foothing.png
Textures are referred to by their complete name, or alternatively by stripping out the file extension:
- e.g.
foomod_foothing.png
- e.g.
foomod_foothing
Supported texture formats are PNG (.png
), JPEG (.jpg
) and Targa (.tga
).
Texture modifiers¶
There are various texture modifiers that can be used to let the client generate textures on-the-fly. The modifiers are applied directly in sRGB colorspace, i.e. without gamma-correction.
Notes¶
TEXMOD_UPSCALE
: The texture with the lower resolution will be automatically upscaled to the higher resolution texture.
Texture overlaying¶
Textures can be overlaid by putting a ^
between them.
Warning: If the lower and upper pixels are both semi-transparent, this operation does not do alpha blending, and it is not associative. Otherwise it does alpha blending in srgb color space.
Example:
default_dirt.png^default_grass_side.png
default_grass_side.png
is overlaid over default_dirt.png
.
See notes: TEXMOD_UPSCALE
Texture grouping¶
Textures can be grouped together by enclosing them in (
and )
.
Example: cobble.png^(thing1.png^thing2.png)
A texture for thing1.png^thing2.png
is created and the resulting
texture is overlaid on top of cobble.png
.
Escaping¶
Modifiers that accept texture names (e.g. [combine
) accept escaping to allow
passing complex texture names as arguments. Escaping is done with backslash and
is required for ^
, :
and \
.
Example: cobble.png^[lowpart:50:color.png\^[mask\:trans.png
Or as a Lua string: "cobble.png^[lowpart:50:color.png\\^[mask\\:trans.png"
The lower 50 percent of color.png^[mask:trans.png
are overlaid
on top of cobble.png
.
Advanced texture modifiers¶
Crack¶
[crack:<n>:<p>
[cracko:<n>:<p>
[crack:<t>:<n>:<p>
[cracko:<t>:<n>:<p>
Parameters:
<t>
: tile count (in each direction)<n>
: animation frame count<p>
: current animation frame
Draw a step of the crack animation on the texture.
crack
draws it normally, while cracko
lays it over, keeping transparent
pixels intact.
Example:
default_cobble.png^[crack:10:1
[combine:<w>x<h>:<x1>,<y1>=<file1>:<x2>,<y2>=<file2>:...
¶
<w>
: width<h>
: height<x>
: x position, negative numbers allowed<y>
: y position, negative numbers allowed<file>
: texture to combine
Creates a texture of size <w>
times <h>
and blits the listed files to their
specified coordinates.
Example:
[combine:16x32:0,0=default_cobble.png:0,16=default_wood.png
[resize:<w>x<h>
¶
Resizes the texture to the given dimensions.
Example:
default_sandstone.png^[resize:16x16
[opacity:<r>
¶
Makes the base image transparent according to the given ratio.
r
must be between 0 (transparent) and 255 (opaque).
Example:
default_sandstone.png^[opacity:127
[invert:<mode>
¶
Inverts the given channels of the base image. Mode may contain the characters "r", "g", "b", "a". Only the channels that are mentioned in the mode string will be inverted.
Example:
default_apple.png^[invert:rgb
[brighten
¶
Brightens the texture.
Example:
tnt_tnt_side.png^[brighten
[noalpha
¶
Makes the texture completely opaque.
Example:
default_leaves.png^[noalpha
[makealpha:<r>,<g>,<b>
¶
Convert one color to transparency.
Example:
default_cobble.png^[makealpha:128,128,128
[transform<t>
¶
<t>
: transformation(s) to apply
Rotates and/or flips the image.
<t>
can be a number (between 0 and 7) or a transform name.
Rotations are counter-clockwise.
0 I identity
1 R90 rotate by 90 degrees
2 R180 rotate by 180 degrees
3 R270 rotate by 270 degrees
4 FX flip X
5 FXR90 flip X then rotate by 90 degrees
6 FY flip Y
7 FYR90 flip Y then rotate by 90 degrees
Example:
default_stone.png^[transformFXR90
[inventorycube{<top>{<left>{<right>
¶
Escaping does not apply here and ^
is replaced by &
in texture names
instead.
Create an inventory cube texture using the side textures.
Example:
[inventorycube{grass.png{dirt.png&grass_side.png{dirt.png&grass_side.png
Creates an inventorycube with grass.png
, dirt.png^grass_side.png
and
dirt.png^grass_side.png
textures
[fill:<w>x<h>:<x>,<y>:<color>
¶
<w>
: width<h>
: height<x>
: x position<y>
: y position<color>
: aColorString
.
Creates a texture of the given size and color, optionally with an <x>,<y>
position. An alpha value may be specified in the Colorstring
.
The optional <x>,<y>
position is only used if the [fill
is being overlaid
onto another texture with '^'.
When [fill
is overlaid onto another texture it will not upscale or change
the resolution of the texture, the base texture will determine the output
resolution.
Examples:
[fill:16x16:#20F02080
texture.png^[fill:8x8:4,4:red
[lowpart:<percent>:<file>
¶
Blit the lower <percent>
% part of <file>
on the texture.
Example:
base.png^[lowpart:25:overlay.png
[verticalframe:<t>:<n>
¶
<t>
: animation frame count<n>
: current animation frame
Crops the texture to a frame of a vertical animation.
Example:
default_torch_animated.png^[verticalframe:16:8
[mask:<file>
¶
Apply a mask to the base image.
The mask is applied using binary AND.
See notes: TEXMOD_UPSCALE
[sheet:<w>x<h>:<x>,<y>
¶
Retrieves a tile at position x, y (in tiles, 0-indexed) from the base image, which it assumes to be a tilesheet with dimensions w, h (in tiles).
[colorize:<color>:<ratio>
¶
Colorize the textures with the given color.
<color>
is specified as a ColorString
.
<ratio>
is an int ranging from 0 to 255 or the word "alpha
". If
it is an int, then it specifies how far to interpolate between the
colors where 0 is only the texture color and 255 is only <color>
. If
omitted, the alpha of <color>
will be used as the ratio. If it is
the word "alpha
", then each texture pixel will contain the RGB of
<color>
and the alpha of <color>
multiplied by the alpha of the
texture pixel.
[colorizehsl:<hue>:<saturation>:<lightness>
¶
Colorize the texture to the given hue. The texture will be converted into a greyscale image as seen through a colored glass, like "Colorize" in GIMP. Saturation and lightness can optionally be adjusted.
<hue>
should be from -180 to +180. The hue at 0° on an HSL color wheel is
red, 60° is yellow, 120° is green, and 180° is cyan, while -60° is magenta
and -120° is blue.
<saturation>
and <lightness>
are optional adjustments.
<lightness>
is from -100 to +100, with a default of 0
<saturation>
is from 0 to 100, with a default of 50
[multiply:<color>
¶
Multiplies texture colors with the given color.
<color>
is specified as a ColorString
.
Result is more like what you'd expect if you put a color on top of another
color, meaning white surfaces get a lot of your new color while black parts
don't change very much.
A Multiply blend can be applied between two textures by using the overlay modifier with a brightness adjustment:
textureA.png^[contrast:0:-64^[overlay:textureB.png
[screen:<color>
¶
Apply a Screen blend with the given color. A Screen blend is the inverse of a Multiply blend, lightening images instead of darkening them.
<color>
is specified as a ColorString
.
A Screen blend can be applied between two textures by using the overlay modifier with a brightness adjustment:
textureA.png^[contrast:0:64^[overlay:textureB.png
[hsl:<hue>:<saturation>:<lightness>
¶
Adjust the hue, saturation, and lightness of the texture. Like "Hue-Saturation" in GIMP, but with 0 as the mid-point.
<hue>
should be from -180 to +180
<saturation>
and <lightness>
are optional, and both percentages.
<lightness>
is from -100 to +100.
<saturation>
goes down to -100 (fully desaturated) but may go above 100,
allowing for even muted colors to become highly saturated.
[contrast:<contrast>:<brightness>
¶
Adjust the brightness and contrast of the texture. Conceptually like GIMP's "Brightness-Contrast" feature but allows brightness to be wound all the way up to white or down to black.
<contrast>
is a value from -127 to +127.
<brightness>
is an optional value, from -127 to +127.
If only a boost in contrast is required, an alternative technique is to hardlight blend the texture with itself, this increases contrast in the same way as an S-shaped color-curve, which avoids dark colors clipping to black and light colors clipping to white:
texture.png^[hardlight:texture.png
[overlay:<file>
¶
Applies an Overlay blend with the two textures, like the Overlay layer mode
in GIMP. Overlay is the same as Hard light but with the role of the two
textures swapped, see the [hardlight
modifier description for more detail
about these blend modes.
See notes: TEXMOD_UPSCALE
[hardlight:<file>
¶
Applies a Hard light blend with the two textures, like the Hard light layer mode in GIMP.
Hard light combines Multiply and Screen blend modes. Light parts of the
<file>
texture will lighten (screen) the base texture, and dark parts of the
<file>
texture will darken (multiply) the base texture. This can be useful
for applying embossing or chiselled effects to textures. A Hard light with the
same texture acts like applying an S-shaped color-curve, and can be used to
increase contrast without clipping.
Hard light is the same as Overlay but with the roles of the two textures
swapped, i.e. A.png^[hardlight:B.png
is the same as B.png^[overlay:A.png
See notes: TEXMOD_UPSCALE
[png:<base64>
¶
Embed a base64 encoded PNG image in the texture string.
You can produce a valid string for this by calling
core.encode_base64(core.encode_png(tex))
,
where tex
is pixel data. Refer to the documentation of these
functions for details.
You can use this to send disposable images such as captchas
to individual clients, or render things that would be too
expensive to compose with [combine:
.
IMPORTANT: Avoid sending large images this way.
This is not a replacement for asset files, do not use it to do anything
that you could instead achieve by just using a file.
In particular consider core.dynamic_add_media
and test whether
using other texture modifiers could result in a shorter string than
embedding a whole image, this may vary by use case.
See notes: TEXMOD_UPSCALE
Hardware coloring¶
The goal of hardware coloring is to simplify the creation of colorful nodes. If your textures use the same pattern, and they only differ in their color (like colored wool blocks), you can use hardware coloring instead of creating and managing many texture files. All of these methods use color multiplication (so a white-black texture with red coloring will result in red-black color).
Static coloring¶
This method is useful if you wish to create nodes/items with the same texture, in different colors, each in a new node/item definition.
Global color¶
When you register an item or node, set its color
field (which accepts a
ColorSpec
) to the desired color.
An ItemStack
's static color can be overwritten by the color
metadata
field. If you set that field to a ColorString
, that color will be used.
Tile color¶
Each tile may have an individual static color, which overwrites every
other coloring method. To disable the coloring of a face,
set its color to white (because multiplying with white does nothing).
You can set the color
property of the tiles in the node's definition
if the tile is in table format.
Palettes¶
For nodes and items which can have many colors, a palette is more suitable. A palette is a texture, which can contain up to 256 pixels. Each pixel is one possible color for the node/item. You can register one node/item, which can have up to 256 colors.
Palette indexing¶
When using palettes, you always provide a pixel index for the given
node or ItemStack
. The palette is read from left to right and from
top to bottom. If the palette has less than 256 pixels, then it is
stretched to contain exactly 256 pixels (after arranging the pixels
to one line). The indexing starts from 0.
Examples:
- 16x16 palette, index = 0: the top left corner
- 16x16 palette, index = 4: the fifth pixel in the first row
- 16x16 palette, index = 16: the pixel below the top left corner
- 16x16 palette, index = 255: the bottom right corner
- 2 (width) x 4 (height) palette, index = 31: the top left corner. The palette has 8 pixels, so each pixel is stretched to 32 pixels, to ensure the total 256 pixels.
- 2x4 palette, index = 32: the top right corner
- 2x4 palette, index = 63: the top right corner
- 2x4 palette, index = 64: the pixel below the top left corner
Using palettes with items¶
When registering an item, set the item definition's palette
field to
a texture. You can also use texture modifiers.
The ItemStack
's color depends on the palette_index
field of the
stack's metadata. palette_index
is an integer, which specifies the
index of the pixel to use.
Linking palettes with nodes¶
When registering a node, set the item definition's palette
field to
a texture. You can also use texture modifiers.
The node's color depends on its param2
, so you also must set an
appropriate paramtype2
:
paramtype2 = "color"
for nodes which use their fullparam2
for palette indexing. These nodes can have 256 different colors. The palette should contain 256 pixels.paramtype2 = "colorwallmounted"
for nodes which use the first five bits (most significant) ofparam2
for palette indexing. The remaining three bits are describing rotation, as inwallmounted
paramtype2. Division by 8 yields the palette index (without stretching the palette). These nodes can have 32 different colors, and the palette should contain 32 pixels. Examples:param2 = 17
is 2 * 8 + 1, so the rotation is 1 and the third (= 2 + 1) pixel will be picked from the palette.param2 = 35
is 4 * 8 + 3, so the rotation is 3 and the fifth (= 4 + 1) pixel will be picked from the palette.
paramtype2 = "colorfacedir"
for nodes which use the first three bits ofparam2
for palette indexing. The remaining five bits are describing rotation, as infacedir
paramtype2. Division by 32 yields the palette index (without stretching the palette). These nodes can have 8 different colors, and the palette should contain 8 pixels. Examples:param2 = 17
is 0 * 32 + 17, so the rotation is 17 and the first (= 0 + 1) pixel will be picked from the palette.param2 = 35
is 1 * 32 + 3, so the rotation is 3 and the second (= 1 + 1) pixel will be picked from the palette.
paramtype2 = "color4dir"
for nodes which use the first six bits ofparam2
for palette indexing. The remaining two bits are describing rotation, as in4dir
paramtype2. Division by 4 yields the palette index (without stretching the palette). These nodes can have 64 different colors, and the palette should contain 64 pixels. Examples:param2 = 17
is 4 * 4 + 1, so the rotation is 1 and the fifth (= 4 + 1) pixel will be picked from the palette.param2 = 35
is 8 * 4 + 3, so the rotation is 3 and the ninth (= 8 + 1) pixel will be picked from the palette.
To colorize a node on the map, set its param2
value (according
to the node's paramtype2).
Conversion between nodes in the inventory and on the map¶
Static coloring is the same for both cases, there is no need for conversion.
If the ItemStack
's metadata contains the color
field, it will be
lost on placement, because nodes on the map can only use palettes.
If the ItemStack
's metadata contains the palette_index
field, it is
automatically transferred between node and item forms by the engine,
when a player digs or places a colored node.
You can disable this feature by setting the drop
field of the node
to itself (without metadata).
To transfer the color to a special drop, you need a drop table.
Example:
core.register_node("mod:stone", {
description = "Stone",
tiles = {"default_stone.png"},
paramtype2 = "color",
palette = "palette.png",
drop = {
items = {
-- assume that mod:cobblestone also has the same palette
{items = {"mod:cobblestone"}, inherit_color = true },
}
}
})
Colored items in craft recipes¶
Craft recipes only support item strings, but fortunately item strings can also contain metadata. Example craft recipe registration:
core.register_craft({
output = core.itemstring_with_palette("wool:block", 3),
type = "shapeless",
recipe = {
"wool:block",
"dye:red",
},
})
To set the color
field, you can use core.itemstring_with_color
.
Metadata field filtering in the recipe
field are not supported yet,
so the craft output is independent of the color of the ingredients.
Soft texture overlay¶
Sometimes hardware coloring is not enough, because it affects the whole tile. Soft texture overlays were added to Luanti to allow the dynamic coloring of only specific parts of the node's texture. For example a grass block may have colored grass, while keeping the dirt brown.
These overlays are 'soft', because unlike texture modifiers, the layers are not merged in the memory, but they are simply drawn on top of each other. This allows different hardware coloring, but also means that tiles with overlays are drawn slower. Using too much overlays might cause FPS loss.
For inventory and wield images you can specify overlays which
hardware coloring does not modify. You have to set inventory_overlay
and wield_overlay
fields to an image name.
To define a node overlay, simply set the overlay_tiles
field of the node
definition. These tiles are defined in the same way as plain tiles:
they can have a texture name, color etc.
To skip one face, set that overlay tile to an empty string.
Example (colored grass block):
core.register_node("default:dirt_with_grass", {
description = "Dirt with Grass",
-- Regular tiles, as usual
-- The dirt tile disables palette coloring
tiles = {{name = "default_grass.png"},
{name = "default_dirt.png", color = "white"}},
-- Overlay tiles: define them in the same style
-- The top and bottom tile does not have overlay
overlay_tiles = {"", "",
{name = "default_grass_side.png"}},
-- Global color, used in inventory
color = "green",
-- Palette in the world
paramtype2 = "color",
palette = "default_foilage.png",
})