summaryrefslogtreecommitdiff
path: root/src/cache-node.c
blob: 6bcb85dbad0decbaf63c05bf9618d4d0a5610e43 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
/*
 *  Copyright (C) 2018-2019 - Vito Caputo - <vcaputo@pengaru.com>
 *
 *  This program is free software: you can redistribute it and/or modify it
 *  under the terms of the GNU General Public License version 3 as published
 *  by the Free Software Foundation.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

#include <assert.h>
#include <stdlib.h>

#include <stage.h>

#include "cache.h"
#include "cache-node.h"
#include "macros.h"


typedef struct cache_node_t {
	cache_t		*cache;
	const m4f_t	*model_x, *view_x, *projection_x;
} cache_node_t;


/* Prepare is where the cache node maintains the cache.  It calls a stage
 * render on the attached stage as part of the outer stage's prepare phase.
 */
static void cache_node_prepare(stage_t *stage, void *object, float alpha, void *render_ctxt)
{
	cache_node_t	*cache_node = object;

	assert(cache_node);

	if (cache_update(cache_node->cache, alpha, render_ctxt))
		stage_dirty(stage);
}


/* Render simply renders a cached texture onto the screen */
static void cache_node_render(const stage_t *stage, void *object, float alpha, void *render_ctxt)
{
	cache_node_t	*cache_node = object;

	assert(stage);
	assert(cache_node);

	cache_render(cache_node->cache, alpha, cache_node->model_x, cache_node->view_x, cache_node->projection_x);
}


static void cache_node_free(const stage_t *stage, void *object)
{
	cache_node_t	*cache_node = object;

	assert(cache_node);

	cache_free(cache_node->cache);
	free(cache_node);
}


static const stage_ops_t cache_node_ops = {
	.prepare_func = cache_node_prepare,
	.render_func = cache_node_render,
	.free_func = cache_node_free,
};


/* return a cache node from an already established cache, with a potentially unique transform */
stage_t * cache_node_new_cache(stage_conf_t *conf, cache_t *cache, const m4f_t *model_x, const m4f_t *view_x, const m4f_t *projection_x)
{
	cache_node_t	*cache_node;
	stage_t		*s;

	assert(conf);

	cache_node = calloc(1, sizeof(cache_node_t));
	fatal_if(!cache_node, "Unable to allocate cache node \"%s\"", conf->name);

	cache_node->cache = cache;
	cache_node->model_x = model_x;
	cache_node->view_x = view_x;
	cache_node->projection_x = projection_x;

	s = stage_new(conf, &cache_node_ops, cache_node);
	fatal_if(!s, "Unable to create stage \"%s\"", conf->name);

	cache_ref(cache);

	return s;
}


/* return a cache node from a stage
 * The cache node takes ownership of the supplied stage, and will
 * free it when the cache node is freed.
 * When the associated stage is dirty, the cache gets updated with its rendered
 * output on a subsequent render, in the prepare hook.
 *
 * region specifies, in ndc coordinates, the region of the canvas as rendered by the associated stage to cache.
 * transform specifies the transformation to apply to the two triangles used for mapping the cached texture.
 * The triangles used for mapping the texture form a section of a unit cube @ coordinates -1,-1,0 .. +1,+1,0, so
 * if you supply an identity matrix for transform, the cached texture is drawn fullscreen.
 *
 * Either region and/or transform may be NULL.  When region is NULL, it's assumed to be -1,-1..+1,+1.  When
 * transform is NULL, it's assumed to be an identity matrix.  So supplying NULL for both caches the full canvas,
 * and draws it directly back into the full canvas.
 */
stage_t * cache_node_new_stage(stage_conf_t *conf, stage_t *stage, const bb2f_t *region, const m4f_t *model_x, const m4f_t *view_x, const m4f_t *projection_x)
{
	cache_t		*cache;

	assert(conf);

	cache = cache_new(stage, region);
	fatal_if(!cache, "Unable to allocate cache \"%s\"", conf->name);

	return cache_node_new_cache(conf, cache, model_x, view_x, projection_x);
}
© All Rights Reserved