Skip to content

Commit

Permalink
drawtexture: add texture reframing support
Browse files Browse the repository at this point in the history
  • Loading branch information
ubitux committed Mar 18, 2024
1 parent 8152f9b commit d56fd82
Show file tree
Hide file tree
Showing 6 changed files with 78 additions and 11 deletions.
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,9 @@ Versioning](https://semver.org/spec/v2.0.0.html) for `libnopegl`.
- `ngl_get_viewport()` to get the viewport currently in use by the rendering
context
- `FontFace.index` parameter to select a different face in the font file
- `DrawTexture.texture` now accepts transformation nodes before the texture node
to serve as a reframing mechanism (the transforms are applied to the texture
coordinates in a centered `[-1,1]` space with `(-1,-1)` in the bottom left)

### Changed
- `Text.font_files` text-based parameter is replaced with `Text.font_faces` node
Expand Down
6 changes: 3 additions & 3 deletions libnopegl/nodes.specs
Original file line number Diff line number Diff line change
Expand Up @@ -1914,14 +1914,14 @@
{
"name": "source",
"type": "node",
"node_types": ["Texture2D"],
"node_types": ["Rotate", "RotateQuat", "Transform", "Translate", "Scale", "Skew", "Texture2D"],
"flags": ["nonull"],
"desc": "source texture to displace"
},
{
"name": "displacement",
"type": "node",
"node_types": ["Texture2D"],
"node_types": ["Rotate", "RotateQuat", "Transform", "Translate", "Scale", "Skew", "Texture2D"],
"flags": ["nonull"],
"desc": "displacement vectors stored in a texture"
},
Expand Down Expand Up @@ -2351,7 +2351,7 @@
{
"name": "texture",
"type": "node",
"node_types": ["Texture2D"],
"node_types": ["Rotate", "RotateQuat", "Transform", "Translate", "Scale", "Skew", "Texture2D"],
"flags": ["nonull"],
"desc": "texture to render"
},
Expand Down
53 changes: 45 additions & 8 deletions libnopegl/src/node_drawother.c
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
#include "pgcraft.h"
#include "pipeline_compat.h"
#include "topology.h"
#include "transforms.h"
#include "type.h"
#include "utils.h"

Expand Down Expand Up @@ -103,6 +104,7 @@ struct pipeline_desc {
struct darray uniforms_map; // struct uniform_map
struct darray blocks_map; // struct resource_map
struct darray textures_map; // struct texture_map
struct darray reframing_nodes; // struct ngl_node *
struct darray uniforms; // struct pgcraft_uniform
};

Expand Down Expand Up @@ -278,11 +280,11 @@ static const struct node_param drawcolor_params[] = {
#define OFFSET(x) offsetof(struct drawdisplace_opts, x)
static const struct node_param drawdisplace_params[] = {
{"source", NGLI_PARAM_TYPE_NODE, OFFSET(source_node),
.node_types=(const uint32_t[]){NGL_NODE_TEXTURE2D, NGLI_NODE_NONE},
.node_types=(const uint32_t[]){TRANSFORM_TYPES_ARGS, NGL_NODE_TEXTURE2D, NGLI_NODE_NONE},
.flags=NGLI_PARAM_FLAG_NON_NULL,
.desc=NGLI_DOCSTRING("source texture to displace")},
{"displacement", NGLI_PARAM_TYPE_NODE, OFFSET(displacement_node),
.node_types=(const uint32_t[]){NGL_NODE_TEXTURE2D, NGLI_NODE_NONE},
.node_types=(const uint32_t[]){TRANSFORM_TYPES_ARGS, NGL_NODE_TEXTURE2D, NGLI_NODE_NONE},
.flags=NGLI_PARAM_FLAG_NON_NULL,
.desc=NGLI_DOCSTRING("displacement vectors stored in a texture")},
COMMON_PARAMS
Expand Down Expand Up @@ -442,7 +444,7 @@ static const struct node_param drawnoise_params[] = {
#define OFFSET(x) offsetof(struct drawtexture_opts, x)
static const struct node_param drawtexture_params[] = {
{"texture", NGLI_PARAM_TYPE_NODE, OFFSET(texture_node),
.node_types=(const uint32_t[]){NGL_NODE_TEXTURE2D, NGLI_NODE_NONE},
.node_types=(const uint32_t[]){TRANSFORM_TYPES_ARGS, NGL_NODE_TEXTURE2D, NGLI_NODE_NONE},
.flags=NGLI_PARAM_FLAG_NON_NULL,
.desc=NGLI_DOCSTRING("texture to render")},
COMMON_PARAMS
Expand Down Expand Up @@ -526,6 +528,7 @@ static void reset_pipeline_desc(void *user_arg, void *data)
ngli_darray_reset(&desc->uniforms_map);
ngli_darray_reset(&desc->blocks_map);
ngli_darray_reset(&desc->textures_map);
ngli_darray_reset(&desc->reframing_nodes);
}

static int init(struct ngl_node *node,
Expand Down Expand Up @@ -620,9 +623,21 @@ static int drawdisplace_init(struct ngl_node *node)
struct drawdisplace_priv *s = node->priv_data;
struct drawdisplace_opts *o = node->opts;

const struct ngl_node *source_node = ngli_transform_get_leaf_node(o->source_node);
if (!source_node) {
LOG(ERROR, "no source texture found at the end of the transform chain");
return NGL_ERROR_INVALID_USAGE;
}

const struct ngl_node *displacement_node = ngli_transform_get_leaf_node(o->displacement_node);
if (!displacement_node) {
LOG(ERROR, "no source texture found at the end of the transform chain");
return NGL_ERROR_INVALID_USAGE;
}

ngli_darray_init(&s->common.draw_resources, sizeof(struct ngl_node *), 0);
if (!ngli_darray_push(&s->common.draw_resources, &o->source_node) ||
!ngli_darray_push(&s->common.draw_resources, &o->displacement_node))
if (!ngli_darray_push(&s->common.draw_resources, &source_node) ||
!ngli_darray_push(&s->common.draw_resources, &displacement_node))
return NGL_ERROR_MEMORY;

return init(node, &s->common, &o->common, "source_displace", source_displace_frag);
Expand Down Expand Up @@ -674,8 +689,14 @@ static int drawtexture_init(struct ngl_node *node)
struct drawtexture_priv *s = node->priv_data;
struct drawtexture_opts *o = node->opts;

const struct ngl_node *texture_node = ngli_transform_get_leaf_node(o->texture_node);
if (!texture_node) {
LOG(ERROR, "no texture found at the end of the transform chain");
return NGL_ERROR_INVALID_USAGE;
}

ngli_darray_init(&s->common.draw_resources, sizeof(struct ngl_node *), 0);
if (!ngli_darray_push(&s->common.draw_resources, &o->texture_node))
if (!ngli_darray_push(&s->common.draw_resources, &texture_node))
return NGL_ERROR_MEMORY;

return init(node, &s->common, &o->common, "source_texture", source_texture_frag);
Expand Down Expand Up @@ -936,6 +957,11 @@ static int drawdisplace_prepare(struct ngl_node *node)
.nb_vert_out_vars = NGLI_ARRAY_NB(vert_out_vars),
};

ngli_darray_init(&desc->reframing_nodes, sizeof(struct ngl_node *), 0);
if (!ngli_darray_push(&desc->reframing_nodes, &o->source_node) ||
!ngli_darray_push(&desc->reframing_nodes, &o->displacement_node))
return NGL_ERROR_MEMORY;

const struct render_common_opts *co = &o->common;
return finalize_pipeline(node, c, co, &crafter_params);
}
Expand Down Expand Up @@ -1140,8 +1166,10 @@ static int drawtexture_prepare(struct ngl_node *node)
if (ret < 0)
return ret;

struct texture_priv *texture_priv = o->texture_node->priv_data;
const struct texture_opts *texture_opts = o->texture_node->opts;
const struct ngl_node *texture_node = ngli_transform_get_leaf_node(o->texture_node);
ngli_assert(texture_node); // already checked in init
struct texture_priv *texture_priv = texture_node->priv_data;
const struct texture_opts *texture_opts = texture_node->opts;
struct pgcraft_texture textures[] = {
{
.name = "tex",
Expand Down Expand Up @@ -1179,6 +1207,10 @@ static int drawtexture_prepare(struct ngl_node *node)
.nb_vert_out_vars = NGLI_ARRAY_NB(vert_out_vars),
};

ngli_darray_init(&desc->reframing_nodes, sizeof(struct ngl_node *), 0);
if (!ngli_darray_push(&desc->reframing_nodes, &o->texture_node))
return NGL_ERROR_MEMORY;

const struct render_common_opts *co = &o->common;
return finalize_pipeline(node, c, co, &crafter_params);
}
Expand Down Expand Up @@ -1268,11 +1300,16 @@ static void drawother_draw(struct ngl_node *node, struct render_common *s, const
ngli_pipeline_compat_update_uniform(pl_compat, uniform_map[i].index, uniform_map[i].data);

struct texture_map *texture_map = ngli_darray_data(&desc->textures_map);
const struct ngl_node **reframing_nodes = ngli_darray_data(&desc->reframing_nodes);
for (size_t i = 0; i < ngli_darray_count(&desc->textures_map); i++) {
if (texture_map[i].image_rev != texture_map[i].image->rev) {
ngli_pipeline_compat_update_image(pl_compat, (int32_t)i, texture_map[i].image);
texture_map[i].image_rev = texture_map[i].image->rev;
}

NGLI_ALIGNED_MAT(reframing_matrix);
ngli_transform_chain_compute(reframing_nodes[i], reframing_matrix);
ngli_pipeline_compat_apply_reframing_matrix(pl_compat, (int32_t)i, texture_map[i].image, reframing_matrix);
}

struct resource_map *resource_map = ngli_darray_data(&desc->blocks_map);
Expand Down
1 change: 1 addition & 0 deletions tests/meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -421,6 +421,7 @@ foreach backend : backends
'3d',
'cubemap',
'cubemap_mipmap',
'reframing',
]

if max_color_attachments >= 4
Expand Down
5 changes: 5 additions & 0 deletions tests/refs/texture_reframing.ref
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
00000000550080005510F490C1C0A080 00000000150080005510F490E180A080 00000000140080005510F490E180A000 000A088A105F038A5DDF748A01DF355F
1E009554A757B614F306C832A983388C 1E009554A7D7B614F386C8F2A383388C 1C809554A7D7B4F4F3C6C2F2A3C32A8C 0882375F77577006F7D2E0D223037C17
0AD517E58E302A8523A0087002020000 0AD517E58E302A8503A0087002000000 0AF507E82A382A8503A0083000800000 0A000FCC7E313A8C07A208E257725DDF
137D9F348AE18E0C23A008E002020004 177D9F1C88E18E0C23A008E002020004 17759F008801880C03A008E002000000 0A202F203AF30A080EA608E257E35D5F
A0001554F5D1F01C8B978C85A0E0A200 A0001554F5D1F01C83978C85A0E0A200 A0001550D5D0D61487968587A1C0A000 002A55DE75D7F01605C720D762027317
21 changes: 21 additions & 0 deletions tests/texture.py
Original file line number Diff line number Diff line change
Expand Up @@ -665,3 +665,24 @@ def texture_mipmap(cfg: ngl.SceneCfg, show_dbg_points=False):
group.add_children(get_debug_points(cfg, cuepoints))

return group


@test_fingerprint(width=320, height=320, keyframes=5, tolerance=1)
@ngl.scene()
def texture_reframing(cfg: ngl.SceneCfg):
cfg.aspect_ratio = (1, 1)
cfg.duration = d = 3

media = load_media("hamster")
anim_pos_kf = [
ngl.AnimKeyFrameVec3(0, (-1, -1, 0)),
ngl.AnimKeyFrameVec3(d / 2, (1, 1, 0)),
ngl.AnimKeyFrameVec3(d, (-1, -1, 0)),
]
anim_angle_kf = [ngl.AnimKeyFrameFloat(0, 0), ngl.AnimKeyFrameFloat(d, 360)]
tex = ngl.Texture2D(data_src=ngl.Media(filename=media.filename))
tex = ngl.Scale(tex, factors=(1.2, 1.2, 1))
tex = ngl.Rotate(tex, angle=ngl.AnimatedFloat(anim_angle_kf))
tex = ngl.Translate(tex, vector=ngl.AnimatedVec3(anim_pos_kf))
geometry = ngl.Quad(corner=(-0.8, -0.8, 0), width=(1.6, 0, 0), height=(0, 1.6, 0))
return ngl.DrawTexture(texture=tex, geometry=geometry)

0 comments on commit d56fd82

Please sign in to comment.