32 std::array<uint32_t, 4> result;
38 }
else if (len == 1) {
41 throw CommandException(
"Expected either 1 or 4 values.");
48 if (propName ==
"-rgba") {
49 std::array<uint32_t, 4> newRGBA = get4(interp, value);
51 }
else if (propName ==
"-rgb") {
52 std::array<uint32_t, 4> newRGB = get4(interp, value);
53 std::array<uint32_t, 4> newRGBA;
55 newRGBA[i] = (rgba[i] & 0x000000ff) |
56 ((newRGB[i] << 8) & 0xffffff00);
59 }
else if (propName ==
"-alpha") {
60 std::array<uint32_t, 4> newAlpha = get4(interp, value);
61 std::array<uint32_t, 4> newRGBA;
63 newRGBA[i] = (rgba[i] & 0xffffff00) |
64 (newAlpha[i] & 0x000000ff);
67 }
else if (propName ==
"-fadePeriod") {
68 updateCurrentFadeValue();
70 }
else if (propName ==
"-fadeTarget") {
71 updateCurrentFadeValue();
72 fadeTarget = std::clamp(value.
getFloat(interp), 0.0f, 1.0f);
73 }
else if (propName ==
"-fadeCurrent") {
74 startFadeValue = std::clamp(value.
getFloat(interp), 0.0f, 1.0f);
76 }
else if (propName ==
"-scrollSpeed") {
77 scrollSpeed = std::max(0.0f, value.
getFloat(interp));
79 }
else if (propName ==
"-scrollPauseLeft") {
80 scrollPauseLeft = std::max(0.0f, value.
getFloat(interp));
81 }
else if (propName ==
"-scrollPauseRight") {
82 scrollPauseRight = std::max(0.0f, value.
getFloat(interp));
83 }
else if (propName ==
"-query-size") {
90void OSDImageBasedWidget::setRGBA(std::span<const uint32_t, 4> newRGBA)
99static void set4(std::span<const uint32_t, 4> rgba, uint32_t mask,
unsigned shift, TclObject& result)
102 result = (rgba[0] & mask) >> shift;
105 return int((rgba[i] & mask) >> shift);
111 if (propName ==
"-rgba") {
112 set4(rgba, 0xffffffff, 0, result);
113 }
else if (propName ==
"-rgb") {
114 set4(rgba, 0xffffff00, 8, result);
115 }
else if (propName ==
"-alpha") {
116 set4(rgba, 0x000000ff, 0, result);
117 }
else if (propName ==
"-fadePeriod") {
119 }
else if (propName ==
"-fadeTarget") {
121 }
else if (propName ==
"-fadeCurrent") {
122 result = getCurrentFadeValue();
123 }
else if (propName ==
"-scrollSpeed") {
124 result = scrollSpeed;
125 }
else if (propName ==
"-scrollPauseLeft") {
126 result = scrollPauseLeft;
127 }
else if (propName ==
"-scrollPauseRight") {
128 result = scrollPauseRight;
129 }
else if (propName ==
"-query-size") {
137std::optional<float> OSDImageBasedWidget::getScrollWidth()
const
139 if (scrollSpeed == 0.0f)
return {};
141 const auto* parentImage =
dynamic_cast<const OSDImageBasedWidget*
>(
getParent());
142 if (!parentImage)
return {};
145 if (!output)
return {};
147 auto [parentPos, parentSize] = parentImage->getBoundingBox(*output);
148 auto parentWidth = parentSize.x / narrow<float>(
getScaleFactor(*output));
151 auto scrollWidth = thisWidth - parentWidth;
152 if (scrollWidth <= 0.0f)
return {};
157bool OSDImageBasedWidget::isAnimating()
const
159 return static_cast<bool>(getScrollWidth());
162[[nodiscard]]
static float smootherStep(
float x)
166 return ((6.0f * x - 15.0f) * x + 10.0f) * x * x * x;
174 auto width = getScrollWidth();
175 if (!width)
return result;
177 auto scrollTime = *width / scrollSpeed;
178 auto animationTime = 2.0f * scrollTime + scrollPauseLeft + scrollPauseRight;
181 auto now = narrow_cast<float>(
Timer::getTime() - startScrollTime) / 1'000'000.0f;
182 auto t = fmodf(now, animationTime);
185 float relOffsetX = [&]{
186 if (
t < scrollPauseLeft) {
189 }
else if (
t < (scrollPauseLeft + scrollTime)) {
191 return smootherStep((
t - scrollPauseLeft) / scrollTime);
192 }
else if (
t < (scrollPauseLeft + scrollTime + scrollPauseRight)) {
197 return smootherStep(1.0f - ((
t - scrollPauseLeft - scrollTime - scrollPauseRight) / scrollTime));
200 result.x -= *width * relOffsetX;
219bool OSDImageBasedWidget::isFading()
const
221 return (startFadeValue != fadeTarget) && (fadePeriod != 0.0f);
226 if (isFading())
return true;
230float OSDImageBasedWidget::getCurrentFadeValue()
const
233 return startFadeValue;
238float OSDImageBasedWidget::getCurrentFadeValue(uint64_t now)
const
240 assert(now >= startFadeTime);
242 auto diff = narrow<int>(now - startFadeTime);
243 assert(fadePeriod != 0.0f);
244 float delta = narrow_cast<float>(diff) / (1000000.0f * fadePeriod);
245 if (startFadeValue < fadeTarget) {
246 float tmp = startFadeValue + delta;
247 if (tmp >= fadeTarget) {
248 startFadeValue = fadeTarget;
249 return startFadeValue;
253 float tmp = startFadeValue - delta;
254 if (tmp <= fadeTarget) {
255 startFadeValue = fadeTarget;
256 return startFadeValue;
262void OSDImageBasedWidget::updateCurrentFadeValue()
266 startFadeValue = getCurrentFadeValue(now);
305 setError(std::move(e).getMessage());
315 "Can't query size: no window visible");
320 vec2 imageSize = [&] {
340 (fadedAlpha != 0) &&
image) {
341 ivec2 drawPos = round(getTransformedPos(output));
342 image->draw(drawPos, fadedAlpha);
Represents the output window/screen of openMSX.
OutputSurface * getOutputSurface()
const OSDTopWidget & getTopWidget() const
A frame buffer where pixels can be written to.
unsigned getListLength(Interpreter &interp) const
TclObject getListIndex(Interpreter &interp, unsigned index) const
float getFloat(Interpreter &interp) const
void addListElement(const T &t)
int getInt(Interpreter &interp) const
uint64_t getTime()
Get current (real) time in us.
This file implemented 3 utility functions:
constexpr void fill(ForwardRange &&range, const T &value)
bool all_equal(InputRange &&range, Proj proj={})
constexpr bool equal(InputRange1 &&range1, InputRange2 &&range2, Pred pred={}, Proj1 proj1={}, Proj2 proj2={})
constexpr auto copy(InputRange &&range, OutputIter out)
constexpr auto transform(Range &&range, UnaryOp op)
constexpr auto xrange(T e)