Skip to content

Commit 710eadc

Browse files
committed
Per-Track and Per-Clip Color
Signed-off-by: Spencer Magnusson <[email protected]>
1 parent 21bd2c9 commit 710eadc

File tree

13 files changed

+521
-13
lines changed

13 files changed

+521
-13
lines changed

src/opentimelineio/CMakeLists.txt

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
set(OPENTIMELINEIO_HEADER_FILES
55
anyDictionary.h
66
anyVector.h
7+
color.h
78
clip.h
89
composable.h
910
composition.h
@@ -38,7 +39,8 @@ set(OPENTIMELINEIO_HEADER_FILES
3839
vectorIndexing.h
3940
version.h)
4041

41-
add_library(opentimelineio ${OTIO_SHARED_OR_STATIC_LIB}
42+
add_library(opentimelineio ${OTIO_SHARED_OR_STATIC_LIB}
43+
color.cpp
4244
clip.cpp
4345
composable.cpp
4446
composition.cpp

src/opentimelineio/clip.cpp

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,11 @@ Clip::Clip(
1515
AnyDictionary const& metadata,
1616
std::vector<Effect*> const& effects,
1717
std::vector<Marker*> const& markers,
18-
std::string const& active_media_reference_key)
18+
std::string const& active_media_reference_key,
19+
Color* color)
1920
: Parent{ name, source_range, metadata, effects, markers }
2021
, _active_media_reference_key(active_media_reference_key)
22+
, _color(color)
2123
{
2224
set_media_reference(media_reference);
2325
}
@@ -144,6 +146,7 @@ Clip::read_from(Reader& reader)
144146
&& reader.read(
145147
"active_media_reference_key",
146148
&_active_media_reference_key)
149+
&& reader.read_if_present("color", &_color)
147150
&& Parent::read_from(reader);
148151
}
149152

@@ -153,6 +156,7 @@ Clip::write_to(Writer& writer) const
153156
Parent::write_to(writer);
154157
writer.write("media_references", _media_references);
155158
writer.write("active_media_reference_key", _active_media_reference_key);
159+
writer.write("color", _color);
156160
}
157161

158162
TimeRange
@@ -211,4 +215,16 @@ Clip::available_image_bounds(ErrorStatus* error_status) const
211215
return active_media->available_image_bounds();
212216
}
213217

218+
Color*
219+
Clip::color() const noexcept
220+
{
221+
return _color;
222+
}
223+
224+
void
225+
Clip::set_color(Color* color)
226+
{
227+
_color = color ? color : new Color();
228+
}
229+
214230
}} // namespace opentimelineio::OPENTIMELINEIO_VERSION

src/opentimelineio/clip.h

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33

44
#pragma once
55

6+
#include "opentimelineio/color.h"
67
#include "opentimelineio/item.h"
78
#include "opentimelineio/mediaReference.h"
89
#include "opentimelineio/version.h"
@@ -46,7 +47,8 @@ class Clip : public Item
4647
AnyDictionary const& metadata = AnyDictionary(),
4748
std::vector<Effect*> const& effects = std::vector<Effect*>(),
4849
std::vector<Marker*> const& markers = std::vector<Marker*>(),
49-
std::string const& active_media_reference_key = default_media_key);
50+
std::string const& active_media_reference_key = default_media_key,
51+
Color* color = nullptr);
5052

5153
/// @name Media References
5254
///@{
@@ -86,6 +88,9 @@ class Clip : public Item
8688
std::optional<IMATH_NAMESPACE::Box2d>
8789
available_image_bounds(ErrorStatus* error_status) const override;
8890

91+
Color* color() const noexcept;
92+
void set_color(Color* color);
93+
8994
protected:
9095
virtual ~Clip();
9196

@@ -103,6 +108,7 @@ class Clip : public Item
103108
private:
104109
std::map<std::string, Retainer<MediaReference>> _media_references;
105110
std::string _active_media_reference_key;
111+
Retainer<Color> _color;
106112
};
107113

108114
}} // namespace opentimelineio::OPENTIMELINEIO_VERSION

src/opentimelineio/color.cpp

Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
// SPDX-License-Identifier: Apache-2.0
2+
// Copyright Contributors to the OpenTimelineIO project
3+
4+
#include <iomanip>
5+
#include <sstream>
6+
7+
#include "opentimelineio/color.h"
8+
9+
namespace opentimelineio { namespace OPENTIMELINEIO_VERSION {
10+
11+
Color::Color(
12+
double const r,
13+
double const g,
14+
double const b,
15+
double const a)
16+
: _r(r),
17+
_g(g),
18+
_b(b),
19+
_a(a) {}
20+
21+
Color::Color(Color const& other) : _r(other.r()),
22+
_g(other.g()),
23+
_b(other.b()),
24+
_a(other.a()) {}
25+
26+
const Color Color::pink(1.0, 0.0, 1.0, 1.0);
27+
const Color Color::red(1.0, 0.0, 0.0, 1.0);
28+
const Color Color::orange(1.0, 0.5, 0.0, 1.0);
29+
const Color Color::yellow(1.0, 1.0, 0.0, 1.0);
30+
const Color Color::green(0.0, 1.0, 0.0, 1.0);
31+
const Color Color::cyan(0.0, 1.0, 1.0, 1.0);
32+
const Color Color::blue(0.0, 0.0, 1.0, 1.0);
33+
const Color Color::purple(0.5, 0.0, 0.5, 1.0);
34+
const Color Color::magenta(1.0, 0.0, 1.0, 1.0);
35+
const Color Color::black(0.0, 0.0, 0.0, 1.0);
36+
const Color Color::white(1.0, 1.0, 1.0, 1.0);
37+
const Color Color::transparent(0.0, 0.0, 0.0, 0.0);
38+
39+
std::string
40+
Color::to_hex()
41+
{
42+
auto rgba = to_rgba_int_list(8);
43+
std::stringstream ss;
44+
ss << "#";
45+
46+
ss << std::hex << std::setfill('0');
47+
ss << std::setw(2) << rgba[0];
48+
ss << std::setw(2) << rgba[1];
49+
ss << std::setw(2) << rgba[2];
50+
ss << std::setw(2) << rgba[3];
51+
return ss.str();
52+
}
53+
54+
std::vector<int>
55+
Color::to_rgba_int_list(int base)
56+
{
57+
double math_base = pow(2, base) - 1.0;
58+
return {int(_r * math_base), int(_g * math_base), int(_b * math_base), int(_a * math_base)};
59+
}
60+
61+
unsigned int
62+
Color::to_agbr_integer()
63+
{
64+
auto rgba = to_rgba_int_list(8);
65+
return (rgba[3] << 24) + (rgba[2] << 16) + (rgba[1] << 8) + rgba[0];
66+
}
67+
68+
std::vector<double>
69+
Color::to_rgba_float_list()
70+
{
71+
return {_r, _g, _b, _a};
72+
}
73+
74+
Color::~Color()
75+
{}
76+
77+
bool
78+
Color::read_from(Reader& reader)
79+
{
80+
return reader.read("r", &_r)
81+
&& reader.read("g", &_g)
82+
&& reader.read("b", &_b)
83+
&& reader.read("a", &_a)
84+
&& Parent::read_from(reader);
85+
}
86+
87+
void
88+
Color::write_to(Writer& writer) const
89+
{
90+
Parent::write_to(writer);
91+
writer.write("r", _r);
92+
writer.write("g", _g);
93+
writer.write("b", _b);
94+
writer.write("a", _a);
95+
}
96+
}} // namespace opentimelineio::OPENTIMELINEIO_VERSION

src/opentimelineio/color.h

Lines changed: 168 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,168 @@
1+
// SPDX-License-Identifier: Apache-2.0
2+
// Copyright Contributors to the OpenTimelineIO project
3+
4+
#pragma once
5+
6+
#include <cmath>
7+
8+
#include "opentimelineio/serializableObjectWithMetadata.h"
9+
#include "opentimelineio/version.h"
10+
11+
namespace opentimelineio { namespace OPENTIMELINEIO_VERSION {
12+
13+
14+
15+
class Color: public SerializableObjectWithMetadata
16+
{
17+
public:
18+
struct Schema
19+
{
20+
static auto constexpr name = "Color";
21+
static int constexpr version = 1;
22+
};
23+
24+
using Parent = SerializableObjectWithMetadata;
25+
26+
Color(double const r = 1.f,
27+
double const g = 1.f,
28+
double const b = 1.f,
29+
double const a = 1.f);
30+
31+
Color(Color const& other);
32+
33+
static const Color pink;
34+
static const Color red;
35+
static const Color orange;
36+
static const Color yellow;
37+
static const Color green;
38+
static const Color cyan;
39+
static const Color blue;
40+
static const Color purple;
41+
static const Color magenta;
42+
static const Color black;
43+
static const Color white;
44+
static const Color transparent;
45+
46+
static Color*
47+
from_hex(std::string const& color) noexcept
48+
{
49+
std::string temp = color;
50+
if (temp[0] == '#')
51+
{
52+
temp = temp.substr(1);
53+
}
54+
else if (temp[0] == '0' and (temp[1] == 'x' or temp[1] == 'X'))
55+
{
56+
temp = temp.substr(2);
57+
}
58+
59+
double _r, _g, _b, _a;
60+
// 0xFFFFFFFF (rgba, 255)
61+
int BASE_16 = 16;
62+
double BASE_16_DIV = 255.0;
63+
double BASE_8_DIV = 15.0;
64+
if (temp.length() == 8)
65+
{
66+
_r = std::stoi(temp.substr(0, 2), nullptr, BASE_16) / BASE_16_DIV;
67+
_g = std::stoi(temp.substr(2, 2), nullptr, BASE_16) / BASE_16_DIV;
68+
_b = std::stoi(temp.substr(4, 2), nullptr, BASE_16) / BASE_16_DIV;
69+
_a = std::stoi(temp.substr(6, 2), nullptr, BASE_16) / BASE_16_DIV;
70+
}
71+
// 0xFFFFFF (rgb, 255)
72+
else if (temp.length() == 6)
73+
{
74+
_r = std::stoi(temp.substr(0, 2), nullptr, BASE_16) / BASE_16_DIV;
75+
_g = std::stoi(temp.substr(2, 2), nullptr, BASE_16) / BASE_16_DIV;
76+
_b = std::stoi(temp.substr(4, 2), nullptr, BASE_16) / BASE_16_DIV;
77+
_a = 1.0;
78+
}
79+
// 0xFFF (rgb, 16)
80+
else if (temp.length() == 3)
81+
{
82+
_r = std::stoi(temp.substr(0, 1), nullptr, BASE_16) / BASE_8_DIV;
83+
_g = std::stoi(temp.substr(1, 1), nullptr, BASE_16) / BASE_8_DIV;
84+
_b = std::stoi(temp.substr(2, 1), nullptr, BASE_16) / BASE_8_DIV;
85+
_a = 1.0;
86+
}
87+
// 0xFFFF (rgba, 16)
88+
else if (temp.length() == 4)
89+
{
90+
_r = std::stoi(temp.substr(0, 1), nullptr, BASE_16) / BASE_8_DIV;
91+
_g = std::stoi(temp.substr(1, 1), nullptr, BASE_16) / BASE_8_DIV;
92+
_b = std::stoi(temp.substr(2, 1), nullptr, BASE_16) / BASE_8_DIV;
93+
_a = std::stoi(temp.substr(3, 1), nullptr, BASE_16) / BASE_8_DIV;
94+
}
95+
else {
96+
throw std::invalid_argument("Invalid hex format");
97+
}
98+
return new Color(_r, _g, _b, _a);
99+
}
100+
101+
static Color*
102+
from_int_list(std::vector<int> const& color, int bit_depth) noexcept
103+
{
104+
double depth = pow(2, bit_depth) - 1.0; // e.g. 8 = 255.0
105+
if (color.size() == 3)
106+
return new Color(color[0] / depth, color[1] / depth, color[2] / depth, 1.0);
107+
else if (color.size() == 4)
108+
return new Color(color[0] / depth, color[1] / depth, color[2] / depth, color[3] / depth);
109+
110+
throw std::invalid_argument("List must have exactly 3 or 4 elements");
111+
}
112+
113+
static Color*
114+
from_agbr_int(unsigned int agbr) noexcept
115+
{
116+
auto conv_r = (agbr & 0xFF) / 255.0;
117+
auto conv_g = ((agbr >> 16) & 0xFF) / 255.0;
118+
auto conv_b = ((agbr >> 8) & 0xFF) / 255.0;
119+
auto conv_a = ((agbr >> 24) & 0xFF) / 255.0;
120+
return new Color(conv_r, conv_g, conv_b, conv_a);
121+
}
122+
123+
static Color*
124+
from_float_list(std::vector<double> const& color) noexcept
125+
{
126+
if (color.size() == 3)
127+
return new Color(color[0], color[1], color[2], 1.0);
128+
else if (color.size() == 4)
129+
return new Color(color[0], color[1], color[2], color[3]);
130+
131+
throw std::invalid_argument("List must have exactly 3 or 4 elements");
132+
}
133+
134+
friend bool
135+
operator==(Color lhs, Color rhs) noexcept
136+
{
137+
return lhs.to_hex() == rhs.to_hex() && lhs.to_agbr_integer() == rhs.to_agbr_integer();
138+
}
139+
140+
std::string to_hex();
141+
std::vector<int> to_rgba_int_list(int base);
142+
unsigned int to_agbr_integer();
143+
std::vector<double> to_rgba_float_list();
144+
145+
double r() const { return _r; }
146+
double g() const { return _g; }
147+
double b() const { return _b; }
148+
double a() const { return _a; }
149+
150+
void set_r(double r) { _r = r; }
151+
void set_g(double g) { _g = g; }
152+
void set_b(double b) { _b = b; }
153+
void set_a(double a) { _a = a; }
154+
155+
protected:
156+
virtual ~Color();
157+
158+
bool read_from(Reader&) override;
159+
void write_to(Writer&) const override;
160+
161+
private:
162+
double _r;
163+
double _g;
164+
double _b;
165+
double _a;
166+
};
167+
168+
}} // namespace opentimelineio::OPENTIMELINEIO_VERSION

0 commit comments

Comments
 (0)