-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathgenerator.go
More file actions
174 lines (154 loc) · 5.78 KB
/
Copy pathgenerator.go
File metadata and controls
174 lines (154 loc) · 5.78 KB
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
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
package stmap
import (
"fmt"
"sort"
)
// GeneratorInfo describes a registered generator with its name and parameter
// definitions. Used by both static and animated generators.
type GeneratorInfo struct {
Name string `json:"name"`
Description string `json:"description"`
Type string `json:"type"` // "static" or "animated"
Params map[string]ParamInfo `json:"params"`
}
// ParamInfo describes a single generator parameter with its default and range.
type ParamInfo struct {
Description string `json:"description"`
Default float64 `json:"default"`
Min float64 `json:"min"`
Max float64 `json:"max"`
}
// --- Static generators ---
// GeneratorFunc creates a static ST map from parameters.
type GeneratorFunc func(params map[string]float64, w, h int) (*STMap, error)
var generators = map[string]GeneratorFunc{}
var generatorInfos = map[string]GeneratorInfo{}
// registerGenerator registers a static generator. Called from init() functions.
func registerGenerator(info GeneratorInfo, fn GeneratorFunc) {
generators[info.Name] = fn
generatorInfos[info.Name] = info
}
// Generate creates a static ST map using the named generator. Unknown params
// are ignored; missing params use defaults from GeneratorInfo.
//
// Width and height must be positive and even, matching NewSTMap. The generators
// build *STMap directly (bypassing NewSTMap), and some divide by w-1/h-1 (e.g.
// corner_pin), so dimensions are validated here to avoid divide-by-zero and the
// corrupt maps that odd dimensions produce under the YUV420 chroma LUT.
func Generate(typeName string, params map[string]float64, w, h int) (*STMap, error) {
fn, ok := generators[typeName]
if !ok {
return nil, fmt.Errorf("stmap: unknown generator type %q", typeName)
}
if !validDimensions(w, h) {
return nil, ErrInvalidDimensions
}
resolved := resolveParams(generatorInfos[typeName], params)
return fn(resolved, w, h)
}
// ListGenerators returns sorted names of all registered static generators.
func ListGenerators() []string {
names := make([]string, 0, len(generators))
for name := range generators {
names = append(names, name)
}
sort.Strings(names)
return names
}
// --- Animated generators ---
// AnimatedGeneratorFunc creates an animated ST map cycle from parameters.
type AnimatedGeneratorFunc func(params map[string]float64, w, h, frameCount int) (*AnimatedSTMap, error)
var animatedGenerators = map[string]AnimatedGeneratorFunc{}
var animatedGeneratorInfos = map[string]GeneratorInfo{}
// registerAnimatedGenerator registers an animated generator. Called from init() functions.
func registerAnimatedGenerator(info GeneratorInfo, fn AnimatedGeneratorFunc) {
animatedGenerators[info.Name] = fn
animatedGeneratorInfos[info.Name] = info
}
// GenerateAnimated creates an animated ST map using the named generator.
// Unknown params are ignored; missing params use defaults from GeneratorInfo.
// Generator metadata (name, resolved params, dimensions) is stored on the
// returned AnimatedSTMap so frames can be regenerated on demand after
// BuildProcessorsCached frees the float32 source data.
func GenerateAnimated(typeName string, params map[string]float64, w, h, frameCount int) (*AnimatedSTMap, error) {
fn, ok := animatedGenerators[typeName]
if !ok {
return nil, fmt.Errorf("stmap: unknown animated generator type %q", typeName)
}
if !validDimensions(w, h) {
return nil, ErrInvalidDimensions
}
resolved := resolveParams(animatedGeneratorInfos[typeName], params)
anim, err := fn(resolved, w, h, frameCount)
if err != nil {
return nil, err
}
// Store generator metadata for on-demand frame regeneration (GPU path).
anim.Generator = typeName
anim.GenParams = resolved
anim.Width = w
anim.Height = h
return anim, nil
}
// ListAnimatedGenerators returns sorted names of all registered animated generators.
func ListAnimatedGenerators() []string {
names := make([]string, 0, len(animatedGenerators))
for name := range animatedGenerators {
names = append(names, name)
}
sort.Strings(names)
return names
}
// resolveParams fills in defaults for any missing parameters.
func resolveParams(info GeneratorInfo, params map[string]float64) map[string]float64 {
resolved := make(map[string]float64, len(info.Params))
for name, p := range info.Params {
resolved[name] = p.Default
}
for k, v := range params {
resolved[k] = v
}
return resolved
}
// AnimatedGeneratorInfoList returns info for all registered animated generators, sorted by name.
func AnimatedGeneratorInfoList() []GeneratorInfo {
infos := make([]GeneratorInfo, 0, len(animatedGeneratorInfos))
for _, info := range animatedGeneratorInfos {
infos = append(infos, info)
}
sort.Slice(infos, func(i, j int) bool {
return infos[i].Name < infos[j].Name
})
return infos
}
// GeneratorInfoList returns all generator info (static and animated) sorted by name.
func GeneratorInfoList() []GeneratorInfo {
infos := make([]GeneratorInfo, 0, len(generatorInfos)+len(animatedGeneratorInfos))
for _, info := range generatorInfos {
infos = append(infos, info)
}
for _, info := range animatedGeneratorInfos {
infos = append(infos, info)
}
sort.Slice(infos, func(i, j int) bool {
return infos[i].Name < infos[j].Name
})
return infos
}
// validDimensions reports whether w and h are valid ST map dimensions: positive
// and even. Even dimensions are required by the YUV420 chroma LUT (cw=w/2), and
// w>=2/h>=2 avoids divide-by-(w-1)/(h-1) in generators like corner_pin. This is
// the same constraint enforced by NewSTMap.
func validDimensions(w, h int) bool {
return w > 0 && h > 0 && w%2 == 0 && h%2 == 0
}
// paramOr returns params[key] if present, otherwise def.
func paramOr(params map[string]float64, key string, def float64) float64 {
if params == nil {
return def
}
if v, ok := params[key]; ok {
return v
}
return def
}