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
|
#include <stdlib.h>
#include <time.h>
#include "fb.h"
#include "rototiller.h"
#include "util.h"
/* Copyright (C) 2019 - Vito Caputo <vcaputo@pengaru.com> */
/* This implements an MTV-inspired random slideshow of rototiller modules.
*
* Eventually it'd be nice to have it show a caption every time a new
* module starts overlaying the name, author, license, etc.
*
* Some TODO items:
* - show captions (need text rendering)
* - optionally persist module contexts so they resume rather than restart
* - runtime-configurable duration
* - randomize runtime settings of shown modules
* - redo the next module selection from random to
* walking the list and randomizing the list every
* time it completes a cycle. The current dumb
* random technique will happily keep showing you the
* same thing over and over.
*/
#define RTV_SNOW_DURATION_SECS 1
#define RTV_DURATION_SECS 15
typedef struct rtv_context_t {
const rototiller_module_t **modules;
size_t n_modules;
time_t next_switch;
const rototiller_module_t *module;
void *module_ctxt;
const rototiller_module_t *snow_module;
} rtv_context_t;
static void setup_next_module(rtv_context_t *ctxt);
static void * rtv_create_context(void);
static void rtv_destroy_context(void *context);
static void rtv_prepare_frame(void *context, unsigned n_cpus, fb_fragment_t *fragment, rototiller_fragmenter_t *res_fragmenter);
static void rtv_finish_frame(void *context, fb_fragment_t *fragment);
rototiller_module_t rtv_module = {
.create_context = rtv_create_context,
.destroy_context = rtv_destroy_context,
.prepare_frame = rtv_prepare_frame,
.finish_frame = rtv_finish_frame,
.name = "rtv",
.description = "Rototiller TV",
.author = "Vito Caputo <vcaputo@pengaru.com>",
.license = "GPLv2",
};
static void setup_next_module(rtv_context_t *ctxt)
{
int i;
/* TODO: most of this module stuff should probably be
* in rototiller.c helpers, but it's harmless for now.
*/
if (ctxt->module) {
if (ctxt->module->destroy_context)
ctxt->module->destroy_context(ctxt->module_ctxt);
ctxt->module_ctxt = NULL;
}
if (ctxt->module != ctxt->snow_module) {
ctxt->module = ctxt->snow_module;
ctxt->next_switch = time(NULL) + RTV_SNOW_DURATION_SECS;
} else {
do {
i = rand() % ctxt->n_modules;
} while (ctxt->modules[i] == &rtv_module ||
ctxt->modules[i] == ctxt->module ||
ctxt->modules[i] == ctxt->snow_module);
ctxt->module = ctxt->modules[i];
ctxt->next_switch = time(NULL) + RTV_DURATION_SECS;
}
if (ctxt->module->create_context)
ctxt->module_ctxt = ctxt->module->create_context();
}
static void * rtv_create_context(void)
{
rtv_context_t *ctxt = calloc(1, sizeof(rtv_context_t));
ctxt->snow_module = rototiller_lookup_module("snow");
rototiller_get_modules(&ctxt->modules, &ctxt->n_modules);
setup_next_module(ctxt);
return ctxt;
}
static void rtv_destroy_context(void *context)
{
free(context);
}
static void rtv_prepare_frame(void *context, unsigned n_cpus, fb_fragment_t *fragment, rototiller_fragmenter_t *res_fragmenter)
{
rtv_context_t *ctxt = context;
if (time(NULL) >= ctxt->next_switch)
setup_next_module(ctxt);
rototiller_module_render(ctxt->module, ctxt->module_ctxt, fragment);
}
static void rtv_finish_frame(void *context, fb_fragment_t *fragment)
{
/* TODO: this is stubbed here for drawing the caption overlay */
}
|