]> git.sesse.net Git - nageru/blob - futatabi/util.h
Fix an issue where scrubbing in Futatabi could lock up if there were no inputs going...
[nageru] / futatabi / util.h
1 #ifndef _UTIL_H
2 #define _UTIL_H 1
3
4 #include <algorithm>
5 #include <math.h>
6 #include <memory>
7 #include <stdint.h>
8
9 struct Vec2 {
10         float du, dv;
11 };
12
13 struct Flow {
14         uint32_t width, height;
15         std::unique_ptr<Vec2[]> flow;
16 };
17
18 Flow read_flow(const char *filename);
19
20 // du and dv are in pixels.
21 inline void flow2rgb(float du, float dv, uint8_t *rr, uint8_t *gg, uint8_t *bb)
22 {
23         float angle = atan2(dv, du);
24         float magnitude = std::min(hypot(du, dv) / 20.0, 1.0);
25
26         // HSV to RGB (from Wikipedia). Saturation is 1.
27         float c = magnitude;
28         float h = (angle + M_PI) * 6.0 / (2.0 * M_PI);
29         float X = c * (1.0 - fabs(fmod(h, 2.0) - 1.0));
30         float r = 0.0f, g = 0.0f, b = 0.0f;
31         if (h <= 1.0f) {
32                 r = c;
33                 g = X;
34         } else if (h <= 2.0f) {
35                 r = X;
36                 g = c;
37         } else if (h <= 3.0f) {
38                 g = c;
39                 b = X;
40         } else if (h <= 4.0f) {
41                 g = X;
42                 b = c;
43         } else if (h <= 5.0f) {
44                 r = X;
45                 b = c;
46         } else if (h <= 6.0f) {
47                 r = c;
48                 b = X;
49         } else {
50                 // h is NaN, so black is fine.
51         }
52         float m = magnitude - c;
53         r += m;
54         g += m;
55         b += m;
56         r = std::max(std::min(r, 1.0f), 0.0f);
57         g = std::max(std::min(g, 1.0f), 0.0f);
58         b = std::max(std::min(b, 1.0f), 0.0f);
59         *rr = lrintf(r * 255.0f);
60         *gg = lrintf(g * 255.0f);
61         *bb = lrintf(b * 255.0f);
62 }
63
64 #endif  // !defined(_UTIL_H)