Skip to content
Permalink
Browse files

Real global textures (#6105)

* Real global textures

* Add world-aligned textures
* Update minimal to support world-aligned tiles
* Update minimal
  • Loading branch information...
numberZero authored and nerzhul committed Oct 15, 2017
1 parent 6bab695 commit 75320e7e88ab5088a46c9e42c1e789cbdacb13b0
@@ -431,7 +431,9 @@ texture_clean_transparent (Clean transparent textures) bool false
# memory. Powers of 2 are recommended. Setting this higher than 1 may not
# have a visible effect unless bilinear/trilinear/anisotropic filtering is
# enabled.
texture_min_size (Minimum texture size for filters) int 64
# This is also used as the base node texture size for world-aligned
# texture autoscaling.
texture_min_size (Minimum texture size) int 64

# Experimental option, might cause visible spaces between blocks
# when set to higher number than 0.
@@ -687,6 +689,22 @@ fog_start (Fog Start) float 0.4 0.0 0.99
# Makes all liquids opaque
opaque_water (Opaque liquids) bool false

# Textures on a node may be aligned either to the node or to the world.
# The former mode suits better things like machines, furniture, etc., while
# the latter makes stairs and microblocks fit surroundings better.
# However, as this possibility is new, thus may not be used by older servers,
# this option allows enforcing it for certain node types. Note though that
# that is considered EXPERIMENTAL and may not work properly.
world_aligned_mode (World-aligned textures mode) enum enable disable,enable,force_solid,force_nodebox

# World-aligned textures may be scaled to span several nodes. However,
# the server may not send the scale you want, especially if you use
# a specially-designed texture pack; with this option, the client tries
# to determine the scale automatically basing on the texture size.
# See also texture_min_size.
# Warning: this option is EXPERIMENTAL!
autoscale_mode (Autoscaling mode) enum disable disable,enable,force

# Show entity selection boxes
show_entity_selectionbox (Show entity selection boxes) bool true

@@ -284,11 +284,19 @@ on top of `cobble.png`.

### Advanced texture modifiers

#### `[crack:<n>:<p>`
#### 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:

@@ -4420,12 +4428,21 @@ Definition tables
* `"image.png"`
* `{name="image.png", animation={Tile Animation definition}}`
* `{name="image.png", backface_culling=bool, tileable_vertical=bool,
tileable_horizontal=bool}`
tileable_horizontal=bool, align_style="node"/"world"/"user", scale=int}`
* backface culling enabled by default for most nodes
* tileable flags are info for shaders, how they should treat texture
when displacement mapping is used
Directions are from the point of view of the tile texture,
not the node it's on
* align style determines whether the texture will be rotated with the node
or kept aligned with its surroundings. "user" means that client
setting will be used, similar to `glasslike_framed_optional`.
Note: supported by solid nodes and nodeboxes only.
* scale is used to make texture span several (exactly `scale`) nodes,
instead of just one, in each direction. Works for world-aligned
textures only.
Note that as the effect is applied on per-mapblock basis, `16` should
be equally divisible by `scale` or you may get wrong results.
* `{name="image.png", color=ColorSpec}`
* the texture's color will be multiplied with this color.
* the tile's color overrides the owning node's color in all cases.
@@ -1,2 +1,2 @@
default

stairs
@@ -501,6 +501,57 @@ minetest.register_node("experimental:tester_node_1", {
end,
})

minetest.register_node("experimental:tiled", {
description = "Tiled stone",
tiles = {{
name = "experimental_tiled.png",
align_style = "world",
scale = 8,
}},
groups = {cracky=2},
})

stairs.register_stair_and_slab("tiled_n", "experimental:tiled",
{cracky=2},
{{name="experimental_tiled.png", align_style="node", scale=8}},
"Tiled stair (node-aligned)",
"Tiled slab (node-aligned)")

stairs.register_stair_and_slab("tiled", "experimantal:tiled",
{cracky=2},
{{name="experimental_tiled.png", align_style="world", scale=8}},
"Tiled stair",
"Tiled slab")

minetest.register_craft({
output = 'experimental:tiled 4',
recipe = {
{'default:cobble', '', 'default:cobble'},
{'', '', ''},
{'default:cobble', '', 'default:cobble'},
}
})

minetest.register_craft({
output = 'stairs:stair_tiled',
recipe = {{'stairs:stair_tiled_n'}}
})

minetest.register_craft({
output = 'stairs:stair_tiled_n',
recipe = {{'stairs:stair_tiled'}}
})

minetest.register_craft({
output = 'stairs:slab_tiled',
recipe = {{'stairs:slab_tiled_n'}}
})

minetest.register_craft({
output = 'stairs:slab_tiled_n',
recipe = {{'stairs:slab_tiled'}}
})

minetest.register_craftitem("experimental:tester_tool_1", {
description = "Tester Tool 1",
inventory_image = "experimental_tester_tool_1.png",
Binary file not shown.
@@ -2,7 +2,7 @@ stairs = {}

-- Node will be called stairs:stair_<subname>
function stairs.register_stair(subname, recipeitem, groups, images, description)
minetest.register_node("stairs:stair_" .. subname, {
minetest.register_node(":stairs:stair_" .. subname, {
description = description,
drawtype = "nodebox",
tiles = images,
@@ -31,7 +31,7 @@ end

-- Node will be called stairs:slab_<subname>
function stairs.register_slab(subname, recipeitem, groups, images, description)
minetest.register_node("stairs:slab_" .. subname, {
minetest.register_node(":stairs:slab_" .. subname, {
description = description,
drawtype = "nodebox",
tiles = images,
@@ -489,6 +489,8 @@
# memory. Powers of 2 are recommended. Setting this higher than 1 may not
# have a visible effect unless bilinear/trilinear/anisotropic filtering is
# enabled.
# This is also used as the base node texture size for world-aligned
# texture autoscaling.
# type: int
# texture_min_size = 64

@@ -808,6 +810,24 @@
# type: bool
# opaque_water = false

# Textures on a node may be aligned either to the node or to the world.
# The former mode sutis better things like machines, furniture, etc., while
# the latter makes stairs and microblocks fit surroundings better.
# However, as this possibility is new, thus may not be used by older servers,
# this option allows enforcing it for certain node types. Note though that
# that is considered EXPERIMENTAL and may not work properly.
# type: enum values: disable, enable, force_solid, force_nodebox
# world_aligned_mode = enable

# World-aligned textures may be scaled to span several nodes. However,
# the server may not send the scale you want, especially if you use
# a specially-designed texture pack; with this option, the client tries
# to determine the scale automatically basing on the texture size.
# See also texture_min_size.
# Warning: this option is EXPERIMENTAL!
# type: enum values: disable, enable, force
# autoscale_mode = disable

# Show entity selection boxes
# type: bool
# show_entity_selectionbox = true
@@ -545,7 +545,7 @@ static void apply_mask(video::IImage *mask, video::IImage *dst,
// Draw or overlay a crack
static void draw_crack(video::IImage *crack, video::IImage *dst,
bool use_overlay, s32 frame_count, s32 progression,
video::IVideoDriver *driver);
video::IVideoDriver *driver, u8 tiles = 1);

// Brighten image
void brighten(video::IImage *image);
@@ -1280,11 +1280,22 @@ bool TextureSource::generateImagePart(std::string part_of_name,
}

// Crack image number and overlay option
// Format: crack[o][:<tiles>]:<frame_count>:<frame>
bool use_overlay = (part_of_name[6] == 'o');
Strfnd sf(part_of_name);
sf.next(":");
s32 frame_count = stoi(sf.next(":"));
s32 progression = stoi(sf.next(":"));
s32 tiles = 1;
// Check whether there is the <tiles> argument, that is,
// whether there are 3 arguments. If so, shift values
// as the first and not the last argument is optional.
auto s = sf.next(":");
if (!s.empty()) {
tiles = frame_count;
frame_count = progression;
progression = stoi(s);
}

if (progression >= 0) {
/*
@@ -1299,7 +1310,7 @@ bool TextureSource::generateImagePart(std::string part_of_name,
if (img_crack) {
draw_crack(img_crack, baseimg,
use_overlay, frame_count,
progression, driver);
progression, driver, tiles);
img_crack->drop();
}
}
@@ -2102,74 +2113,78 @@ static void apply_mask(video::IImage *mask, video::IImage *dst,
}
}

video::IImage *create_crack_image(video::IImage *crack, s32 frame_index,
core::dimension2d<u32> size, u8 tiles, video::IVideoDriver *driver)
{
core::dimension2d<u32> strip_size = crack->getDimension();
core::dimension2d<u32> frame_size(strip_size.Width, strip_size.Width);
core::dimension2d<u32> tile_size(size / tiles);
s32 frame_count = strip_size.Height / strip_size.Width;
if (frame_index >= frame_count)
frame_index = frame_count - 1;
core::rect<s32> frame(v2s32(0, frame_index * frame_size.Height), frame_size);
video::IImage *result = nullptr;

// extract crack frame
video::IImage *crack_tile = driver->createImage(video::ECF_A8R8G8B8, tile_size);
if (!crack_tile)
return nullptr;
if (tile_size == frame_size) {
crack->copyTo(crack_tile, v2s32(0, 0), frame);
} else {
video::IImage *crack_frame = driver->createImage(video::ECF_A8R8G8B8, frame_size);
if (!crack_frame)
goto exit__has_tile;
crack->copyTo(crack_frame, v2s32(0, 0), frame);
crack_frame->copyToScaling(crack_tile);
crack_frame->drop();
}
if (tiles == 1)
return crack_tile;

// tile it
result = driver->createImage(video::ECF_A8R8G8B8, size);
if (!result)
goto exit__has_tile;
result->fill({});
for (u8 i = 0; i < tiles; i++)
for (u8 j = 0; j < tiles; j++)
crack_tile->copyTo(result, v2s32(i * tile_size.Width, j * tile_size.Height));

exit__has_tile:
crack_tile->drop();
return result;
}

static void draw_crack(video::IImage *crack, video::IImage *dst,
bool use_overlay, s32 frame_count, s32 progression,
video::IVideoDriver *driver)
video::IVideoDriver *driver, u8 tiles)
{
// Dimension of destination image
core::dimension2d<u32> dim_dst = dst->getDimension();
// Dimension of original image
core::dimension2d<u32> dim_crack = crack->getDimension();
// Count of crack stages
s32 crack_count = dim_crack.Height / dim_crack.Width;
// Limit frame_count
if (frame_count > (s32) dim_dst.Height)
frame_count = dim_dst.Height;
if (frame_count < 1)
frame_count = 1;
// Limit progression
if (progression > crack_count-1)
progression = crack_count-1;
// Dimension of a single crack stage
core::dimension2d<u32> dim_crack_cropped(
dim_crack.Width,
dim_crack.Width
);
// Dimension of the scaled crack stage,
// which is the same as the dimension of a single destination frame
core::dimension2d<u32> dim_crack_scaled(
core::dimension2d<u32> frame_size(
dim_dst.Width,
dim_dst.Height / frame_count
);
// Create cropped and scaled crack images
video::IImage *crack_cropped = driver->createImage(
video::ECF_A8R8G8B8, dim_crack_cropped);
video::IImage *crack_scaled = driver->createImage(
video::ECF_A8R8G8B8, dim_crack_scaled);
video::IImage *crack_scaled = create_crack_image(crack, progression,
frame_size, tiles, driver);
if (!crack_scaled)
return;

if (crack_cropped && crack_scaled)
{
// Crop crack image
v2s32 pos_crack(0, progression*dim_crack.Width);
crack->copyTo(crack_cropped,
v2s32(0,0),
core::rect<s32>(pos_crack, dim_crack_cropped));
// Scale crack image by copying
crack_cropped->copyToScaling(crack_scaled);
// Copy or overlay crack image onto each frame
for (s32 i = 0; i < frame_count; ++i)
{
v2s32 dst_pos(0, dim_crack_scaled.Height * i);
if (use_overlay)
{
blit_with_alpha_overlay(crack_scaled, dst,
v2s32(0,0), dst_pos,
dim_crack_scaled);
}
else
{
blit_with_alpha(crack_scaled, dst,
v2s32(0,0), dst_pos,
dim_crack_scaled);
}
}
auto blit = use_overlay ? blit_with_alpha_overlay : blit_with_alpha;
for (s32 i = 0; i < frame_count; ++i) {
v2s32 dst_pos(0, frame_size.Height * i);
blit(crack_scaled, dst, v2s32(0,0), dst_pos, frame_size);
}

if (crack_scaled)
crack_scaled->drop();

if (crack_cropped)
crack_cropped->drop();
crack_scaled->drop();
}

void brighten(video::IImage *image)
@@ -209,7 +209,8 @@ struct TileLayer
texture_id == other.texture_id &&
material_type == other.material_type &&
material_flags == other.material_flags &&
color == other.color;
color == other.color &&
scale == other.scale;
}

/*!
@@ -298,6 +299,8 @@ struct TileLayer
* a color then the color of the node owning this tile.
*/
video::SColor color;

u8 scale;
};

/*!
@@ -325,6 +328,9 @@ struct TileSpec
&& emissive_light == other.emissive_light;
}

//! If true, the tile rotation is ignored.
bool world_aligned = false;
//! Tile rotation.
u8 rotation = 0;
//! This much light does the tile emit.
u8 emissive_light = 0;
Oops, something went wrong.

0 comments on commit 75320e7

Please sign in to comment.
You can’t perform that action at this time.