Conversation
styles/layers.h
Outdated
| }; | ||
|
|
||
| // Solid+solid check | ||
| template<class BASE, class L1> |
There was a problem hiding this comment.
Isn't it true that no layer except the first one should be solid?
There was a problem hiding this comment.
hmm. would "“Reject solid layers after the first is found" be a better comment?
This would go away anyway with a move to color.h
There was a problem hiding this comment.
I'm saying that we don't need to make so many changes, we can just insert the assert into Compose<>
Basically, if the second argument to Compose is opaque -> error
styles/layers.h
Outdated
| #include <utility> | ||
|
|
||
| // Identify “solid” colors by the return type of getColor() | ||
| namespace layers_detail { |
There was a problem hiding this comment.
This seems like it could be useful in lots of places, so maybe call it color_details and put it in common/color.h instead?
styles/style_ptr.h
Outdated
| template<class T> struct TopBase { using type = T; }; | ||
| template<class B, class L> struct TopBase<Compose<B,L>> : TopBase<B> {}; | ||
|
|
||
| template<typename T> struct IsOpaqueColor : std::false_type {}; |
There was a problem hiding this comment.
This is the same code as in layers_details, so it should definitely go in common/color.h
And make messages obnoxiously visible so they are easy to find in a sea of "ambiguous overload" errors.
And make messages obnoxiously visible so they are easy to find in a sea of "ambiguous overload" errors.
|
I also made messages obnoxiously visible so they are easy to find in a sea of "ambiguous overload" errors. |
styles/layers.h
Outdated
| }; | ||
|
|
||
| // Solid+solid check | ||
| template<class BASE, class L1> |
There was a problem hiding this comment.
I'm saying that we don't need to make so many changes, we can just insert the assert into Compose<>
Basically, if the second argument to Compose is opaque -> error
also cover scenarios for Black and Alpha 0 being first
styles/layers.h
Outdated
| public: | ||
| using _BaseColorT = decltype(std::declval<BASE&>().getColor(0)); | ||
| using _LayerColorT = decltype(std::declval<L1&>().getColor(0)); | ||
| static_assert(!(color_details::IsOpaqueColor<_BaseColorT>::value && |
There was a problem hiding this comment.
I think it's enough to just check if _LayerColorT is opaque.
It doesn't matter if _BaseColorT is opaque or not.
styles/layers.h
Outdated
| public: | ||
| static_assert(!color_details::IsOpaqueColor<decltype(std::declval<L1&>().getColor(0))>::value, | ||
| "\n\n" | ||
| "*** Layers<> ERROR: CANNOT STACK TWO SOLID COLORS.\n\n"); |
There was a problem hiding this comment.
This error needs updating now.
Something like "Layers<> error: Only the base color may be solid" maybe?
styles/layers.h
Outdated
| template<class BASE, class L1> | ||
| class Compose { | ||
| public: | ||
| static_assert(!color_details::IsOpaqueColor<decltype(std::declval<L1&>().getColor(0))>::value, |
There was a problem hiding this comment.
Should be indented two more steps.
There was a problem hiding this comment.
Doesn't look fixed.
Note, I'm talking about the static_assert itself, not the string inside it.
styles/layers.h
Outdated
| // Drop fully transparent first item (Alpha 0) when there are exactly 2 args. | ||
| template<class BASE, class L1> struct LayerSelector<AlphaL<BASE, Int<0>>, L1> { typedef L1 type; }; | ||
|
|
||
| // Drop fully transparent first item (Alpha 0) when there are 3+ args. |
There was a problem hiding this comment.
I think the correct fix for this is to change line 82 from:
typedef typename LayerSelector<Compose<BASE, L1>, REST...>::type type;
to
typedef typename LayerSelector<LayerSelector<BASE, L1>::type, REST...>::type type;
I think that's what I originally intended anyways.
That way everything gets broken down into two-layer calls to LayerSelector, and we don't have to special-case three-layer stuff.
There was a problem hiding this comment.
I think that means we don't need this 3-layer case anymore.
There was a problem hiding this comment.
oops. actually deleted this time.
styles/style_ptr.h
Outdated
| // Get a pointer to class. | ||
| template<class STYLE> | ||
| StyleAllocator StylePtr() { | ||
| using _TopBaseT = typename style_base_check_detail::TopBase<STYLE>::type; |
There was a problem hiding this comment.
Now that Layers<> can't become magically opaque anymore, we can remove this, right?
Edit:.. see below first
styles/style_ptr.h
Outdated
| using _TopBaseCol = decltype(std::declval<_TopBaseT&>().getColor(0)); | ||
| static_assert(color_details::IsOpaqueColor<_TopBaseCol>::value, | ||
| "\n\n" | ||
| "*** StylePtr<> error: BASE LAYER MUST BE A SOLID COLOR, NOT TRANSPARENT.\n" |
There was a problem hiding this comment.
This might be confusing if the argument to styleptr is not a layer.
How about we move the actual assert into style_base_check_detail, and we'll make one error message if the argument is Layers<> with a transparent base, and another error message if it's something else that is transparent?
That should also give us a little bit more code reuse since this is currently repeated in StyleChargingPtr<>
There was a problem hiding this comment.
another error message if it's something else that is transparent
hmm, meaning something like
AudioFlicker<AlphaL<Blue,Int<16000>>,AlphaL<Red,Int<16000>>> ?
How about we just leave the single message but remove "layer" from it so it just says "base must" - that covers a transparent style or a Layer.
"StylePtr<> error: BASE MUST BE A SOLID COLOR, NOT TRANSPARENT
There was a problem hiding this comment.
I would use STYLE instead of BASE in that case.
(And I don't think we need the whole error to be allcaps.)
There was a problem hiding this comment.
Since we still depend on finding the true base type buried inside Layers<>, TopBase seems to still be required. Otherwise a style of
StylePtr<Layers< AlphaL<Yellow,Int<9000>>, Red>>(), prints
"Layers<> error: Only the base color may be solid."
not the one it should, the
"StylePtr<> error: Style must be a solid color, not transparent." one.
After tonight's latest edits we have:
-
A transparent style with no layers like
StylePtr<AudioFlicker<AlphaL<Blue,Int<16000>>,AlphaL<Red,Int<16000>>>>()
shows:
"*** StylePtr<> error: Style must be a solid color, not transparent." -
A Layers<> style with a transparent first color like
StylePtr<Layers< AlphaL<Yellow,Int<9000>>, Red, AlphaL<Blue,Int<16000>>>>()
shows:
"*** StylePtr<> error: Style must be a solid color, not transparent." -
A Layers<> style with an Alpha Zero first color gets a pass and compiles.
-
A Layers<> style with Black as the first color gets a pass and compiles.
-
A Layers<> style with Black and an Alpha Zero as the first 2 colors (in either order) gets a pass and compiles.
-
A Layers<> style with more than 2 solid colors anywhere shows:
"*** Layers<> error: Only the base color may be solid."
That's how it should be working, right?
There was a problem hiding this comment.
I don't think we need the whole error to be all caps.
Are you sure I can't sell you on the great visibility the marquee style provides in the sea of errors?
Comparison:
ProffieOS-v8.x/ProffieOS/styles/style_ptr.h:99:8: error: 'bool Style<T>::IsHandled(HandledFeature) [with T = Compose<AlphaL<Rgb<255, 255, 0>, SingleValueAdapter<IntSVF<5000> > >, Rgb<255, 0, 0> >]' marked 'override', but does not override
99 | bool IsHandled(HandledFeature effect) override {
| ^~~~~~~~~
ProffieOS-v8.x/ProffieOS/styles/style_ptr.h:107:8: error: 'void Style<T>::run(BladeBase*) [with T = Compose<AlphaL<Rgb<255, 255, 0>, SingleValueAdapter<IntSVF<5000> > >, Rgb<255, 0, 0> >]' marked 'override', but does not override
107 | void run(BladeBase* blade) override {
| ^~~
ProffieOS-v8.x/ProffieOS/styles/style_ptr.h:113:7: error: 'int Style<T>::get_max_arg(int) [with T = Compose<AlphaL<Rgb<255, 255, 0>, SingleValueAdapter<IntSVF<5000> > >, Rgb<255, 0, 0> >]' marked 'override', but does not override
113 | int get_max_arg(int argument) override {
| ^~~~~~~~~~~
In file included from ProffieOS-v8.x/ProffieOS/styles/fire.h:4,
from ProffieOS-v8.x/ProffieOS/ProffieOS.ino:624:
ProffieOS-v8.x/ProffieOS/styles/style_ptr.h: In instantiation of 'void style_base_check_detail::AssertLayersBaseOpaque() [with STYLE = Compose<AlphaL<Rgb<255, 255, 0>, SingleValueAdapter<IntSVF<5000> > >, Rgb<255, 0, 0> >]':
ProffieOS-v8.x/ProffieOS/styles/style_ptr.h:160:57: required from 'StyleFactory* StylePtr() [with STYLE = Compose<AlphaL<Rgb<255, 255, 0>, SingleValueAdapter<IntSVF<5000> > >, Rgb<255, 0, 0> >]'
ProffieOS-v8.x/ProffieOS/config/BC_Ronin_8.x.h:430:74: required from here
ProffieOS-v8.x/ProffieOS/styles/style_ptr.h:15:62: error: static assertion failed:
*** StylePtr<> error: Style must be a solid color, not transparent.
15 | static_assert(color_details::IsOpaqueColor<_TopBaseCol>::value,
| ^~~~~
In file included from ProffieOS-v8.x/ProffieOS/blades/blade_base.h:20,
from ProffieOS-v8.x/ProffieOS/ProffieOS.ino:587:
ProffieOS-v8.x/ProffieOS/styles/blade_style.h: In instantiation of 'BladeStyle* StyleFactoryImpl<STYLE>::make() [with STYLE = Style<Compose<AlphaL<Rgb<255, 255, 0>, SingleValueAdapter<IntSVF<5000> > >, Rgb<255, 0, 0> > >]':
ProffieOS-v8.x/ProffieOS/styles/blade_style.h:45:15: required from here
ProffieOS-v8.x/ProffieOS/styles/blade_style.h:47:22: error: cannot convert 'Style<Compose<AlphaL<Rgb<255, 255, 0>, SingleValueAdapter<IntSVF<5000> > >, Rgb<255, 0, 0> > >*' to 'BladeStyle*' in return
47 | return new STYLE();
| ^
exit status 1
Error compiling for board Proffieboard V2.
or
ProffieOS-v8.x/ProffieOS/styles/style_ptr.h:99:8: error: 'bool Style<T>::IsHandled(HandledFeature) [with T = Compose<AlphaL<Rgb<255, 255, 0>, SingleValueAdapter<IntSVF<5000> > >, Rgb<255, 0, 0> >]' marked 'override', but does not override
99 | bool IsHandled(HandledFeature effect) override {
| ^~~~~~~~~
ProffieOS-v8.x/ProffieOS/styles/style_ptr.h:107:8: error: 'void Style<T>::run(BladeBase*) [with T = Compose<AlphaL<Rgb<255, 255, 0>, SingleValueAdapter<IntSVF<5000> > >, Rgb<255, 0, 0> >]' marked 'override', but does not override
107 | void run(BladeBase* blade) override {
| ^~~
ProffieOS-v8.x/ProffieOS/styles/style_ptr.h:113:7: error: 'int Style<T>::get_max_arg(int) [with T = Compose<AlphaL<Rgb<255, 255, 0>, SingleValueAdapter<IntSVF<5000> > >, Rgb<255, 0, 0> >]' marked 'override', but does not override
113 | int get_max_arg(int argument) override {
| ^~~~~~~~~~~
In file included from ProffieOS-v8.x/ProffieOS/styles/fire.h:4,
from ProffieOS-v8.x/ProffieOS/ProffieOS.ino:624:
ProffieOS-v8.x/ProffieOS/styles/style_ptr.h: In instantiation of 'void style_base_check_detail::AssertLayersBaseOpaque() [with STYLE = Compose<AlphaL<Rgb<255, 255, 0>, SingleValueAdapter<IntSVF<5000> > >, Rgb<255, 0, 0> >]':
ProffieOS-v8.x/ProffieOS/styles/style_ptr.h:160:57: required from 'StyleFactory* StylePtr() [with STYLE = Compose<AlphaL<Rgb<255, 255, 0>, SingleValueAdapter<IntSVF<5000> > >, Rgb<255, 0, 0> >]'
ProffieOS-v8.x/ProffieOS/config/BC_Ronin_8.x.h:430:74: required from here
ProffieOS-v8.x/ProffieOS/styles/style_ptr.h:15:62: error: static assertion failed:
--------------------------------------------------------------------------
| |
| StylePtr<> error: Style must be a solid color, not transparent |
| |
--------------------------------------------------------------------------
15 | static_assert(color_details::IsOpaqueColor<_TopBaseCol>::value,
| ^~~~~
In file included from ProffieOS-v8.x/ProffieOS/blades/blade_base.h:20,
from ProffieOS-v8.x/ProffieOS/ProffieOS.ino:587:
ProffieOS-v8.x/ProffieOS/styles/blade_style.h: In instantiation of 'BladeStyle* StyleFactoryImpl<STYLE>::make() [with STYLE = Style<Compose<AlphaL<Rgb<255, 255, 0>, SingleValueAdapter<IntSVF<5000> > >, Rgb<255, 0, 0> > >]':
ProffieOS-v8.x/ProffieOS/styles/blade_style.h:45:15: required from here
ProffieOS-v8.x/ProffieOS/styles/blade_style.h:47:22: error: cannot convert 'Style<Compose<AlphaL<Rgb<255, 255, 0>, SingleValueAdapter<IntSVF<5000> > >, Rgb<255, 0, 0> > >*' to 'BladeStyle*' in return
47 | return new STYLE();
| ^
exit status 1
Error compiling for board Proffieboard V2.
There was a problem hiding this comment.
Not that my opinion matters, but I personally like the "framed" error much better than the one with "***".
styles/layers.h
Outdated
| // If the base color is opqaque, the final result of this style will also be | ||
| // opaque. If the base color is transparent, the final result may also be transparent, | ||
| // depending on what the layers paint on top of the base color. | ||
| // This style works like layers in Photoshop: each layer is painted over the one beneath it. |
There was a problem hiding this comment.
"beneath it" can be confusing, does it refer to the order of rending or the order of writing?
Not sure what a better way to describe it would be though...
There was a problem hiding this comment.
Agreed. Unfortunately, it's true that "underneath" and "above" are equally correct for a way to describe layer order. I find myself thinking in terms of front to back, not top to bottom. So layers are (as it hints) like photoshop layers.
Therefore, the base layer is "behind" the other layers that are "in front of" it.
There was a problem hiding this comment.
It can be made explicit with an example though:
Layers<A, B, C>
B is painted on top of A, and then C is painted on top of that.
There was a problem hiding this comment.
I reworded a bit without the A, B, C example. Does it read well enough now?
styles/layers.h
Outdated
| template<class BASE, class L1> | ||
| class Compose { | ||
| public: | ||
| static_assert(!color_details::IsOpaqueColor<decltype(std::declval<L1&>().getColor(0))>::value, |
There was a problem hiding this comment.
Doesn't look fixed.
Note, I'm talking about the static_assert itself, not the string inside it.
styles/layers.h
Outdated
| template<class BASE, class ABASE> | ||
| struct LayerSelector<BASE, AlphaL<ABASE, Int<0>>> { typedef BASE type; }; | ||
|
|
||
| // Drop BLACK when it’s first (two-arg case). |
There was a problem hiding this comment.
This doesn't work, because the layer will be transparent.
Also, we already have a special case for BLACK in Compose<>
There was a problem hiding this comment.
That's right.
I got lost in all these scenarios.
| template<class B, class L> struct TopBase<Compose<B,L>> : TopBase<B> {}; | ||
| template<class STYLE> | ||
| inline void AssertLayersBaseOpaque() { | ||
| using _TopBaseT = typename TopBase<STYLE>::type; |
There was a problem hiding this comment.
I don't think we need this, we can just check if STYLE is transparent.
There was a problem hiding this comment.
I tried that, but it doesn’t correctly catch the case where a Layers<> starts with a transparent color because by the time the check runs, it already combined with the next layer, so we get the Layers error instead of the intended “Style must be solid color, not transparent” error.
With the TopBase check, we can directly see the very first color and report the right error message.
There was a problem hiding this comment.
That would only happen if you have a transparent base and a solid layer somewhere after, right?
Isn't that a highly unusual case?
There was a problem hiding this comment.
I would say yes. I was testing using
StylePtr<Layers< AlphaL<Yellow,Int<9000>>, Red, AlphaL<Blue,Int<16000>>>>()
But you've conditioned me to cover all the what-ifs.
There was a problem hiding this comment.
When there are two errors in the code, I don't think we should be particularly picky about which one shows up.
styles/layers.h
Outdated
| // If the base color is opqaque, the final result of this style will also be | ||
| // opaque. If the base color is transparent, the final result may also be transparent, | ||
| // depending on what the layers paint on top of the base color. | ||
| // This style works like layers in Photoshop: each layer adds to the stack covering the base. |
There was a problem hiding this comment.
Why replace "photoshop or gimp" with "photoshop"?
I don't know anybody who uses photoshop anymore, since gimp and krita are free and just as good in most cases.
There was a problem hiding this comment.
I glazed right over that it even said Gimp.
Restored.
styles/layers.h
Outdated
| // This style works like layers in Photoshop: each layer adds to the stack covering the base. | ||
| // The written order of layers in the blade style code puts the base first, with any following layers visually covering it. | ||
| // | ||
| // When a Layers<> is used as the first template argument to StylePtr<>, its BASE color (the first layer) |
There was a problem hiding this comment.
I'm not a fan of how this is written.
I think it would be better to explain that the output of Layers<> is opaque iff the base layer opaque.
Then we can explain that StylePtr<> it's argument to be opaque, so therefore StylePtr<Layers<BASE, ... >> requires BASE to be opaque.
The way it's written now, you can sort of infer what happens if the base layer is transparent, but it's never actually explained.
styles/layers.h
Outdated
| // When a Layers<> is used as the first template argument to StylePtr<>, its BASE color (the first layer) | ||
| // must be a solid (opaque) color, not transparent. No additional solid colors may be stacked on top | ||
| // of that solid base. | ||
| // Additional layers stacked on top of a solid base color are transparent, |
| template<class B, class L> struct TopBase<Compose<B,L>> : TopBase<B> {}; | ||
| template<class STYLE> | ||
| inline void AssertLayersBaseOpaque() { | ||
| using _TopBaseT = typename TopBase<STYLE>::type; |
There was a problem hiding this comment.
When there are two errors in the code, I don't think we should be particularly picky about which one shows up.
Just compile time error messages that are user friendly.